internal void CertifyExistingForJava(int chainLen) { DeviceBundle bundle = new DeviceBundle(); bundle.AliasCert = (X509Certificate)Helpers.ReadPemObject(ToPath(Program.AliasCert)); bundle.DeviceIDPublic = (AsymmetricKeyParameter)Helpers.ReadPemObject(ToPath(Program.DeviceIDPublic)); // The current Java implementation stores the public and provate keys separately. Put them back // together ECPrivateKeyParameters opriv = (ECPrivateKeyParameters)Helpers.ReadPemObject(ToPath("AliasPrivate.PEM")); ECPublicKeyParameters opub = (ECPublicKeyParameters)Helpers.ReadPemObject(ToPath("AliasPublic.PEM")); AsymmetricCipherKeyPair kpx = new AsymmetricCipherKeyPair(opub, opriv); Helpers.WritePEMObject(ToPath(Program.AliasKey), kpx); bundle.AliasKeyPair = (AsymmetricCipherKeyPair)Helpers.ReadPemObject(ToPath(Program.AliasKey)); MakeCertChain(bundle, chainLen, 0); }
internal void MakeCertChain(DeviceBundle bundle, int chainLen, int fwidSeed) { var aliasCert = bundle.AliasCert; DateTime now = DateTime.Now; byte[] fwid = Helpers.HashData(new byte[1] { 0 }, 0, 1); const int keyStrength = 256; CryptoApiRandomGenerator rg = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(rg); KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new ECKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); // Starting the loop we have a (not yet certified) DeviceID public key // and the Issuer of the Alias Cert (which we want to be the DevID-cert DN.) List <X509Certificate> certChain = new List <X509Certificate>(); var lastCertIssuer = aliasCert.IssuerDN; var lastPubKey = bundle.DeviceIDPublic;; AsymmetricCipherKeyPair lastKeyPair = null; for (int j = 0; j < chainLen; j++) { bool rootCert = j == chainLen - 1; bool lastButOne = j == chainLen - 2; AsymmetricCipherKeyPair caKey = keyPairGenerator.GenerateKeyPair(); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.SetSerialNumber(new BigInteger(new byte[] { 1, 2, 3, 4, 5 })); var issuerDn = lastButOne ? new X509Name($"CN=Vendor Root CA O=MSR_TEST, C=US") : new X509Name($"CN=Vendor Intermediate CA {j}, O=MSR_TEST, C=US"); if (rootCert) { issuerDn = lastCertIssuer; } certGen.SetIssuerDN(issuerDn); certGen.SetSubjectDN(lastCertIssuer); certGen.SetNotBefore(now); certGen.SetNotAfter(now + new TimeSpan(365 * 10, 0, 0, 0, 0)); certGen.SetPublicKey(lastPubKey); int pathLengthConstraint = j + 1; certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(pathLengthConstraint)); certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.KeyCertSign)); X509Certificate certificate; if (rootCert) { ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", lastKeyPair.Private, random); certificate = certGen.Generate(signatureFactory); } else { ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", caKey.Private, random); certificate = certGen.Generate(signatureFactory); } lastCertIssuer = certificate.IssuerDN; lastPubKey = caKey.Public; lastKeyPair = caKey; certChain.Add(certificate); } // Chain including root, but not AliasCert. NOTE, finishes with CA Helpers.WritePEMObjects(ToPath(Program.DeviceCertChain), certChain.ToArray()); // cert chain including AliasCert (alias cert is first. CA is last) JoinFiles(Program.AliasCert, Program.DeviceCertChain, Program.DeviceCertChainIncAlias); // just the device CA (for the server) Helpers.WritePEMObject(ToPath("DeviceCA.pem"), certChain.Last()); // Now make some certs for the server to use string serverCaName = "CN=Server CA, C=US, O=MSR_TEST"; string serverName = "CN=Server Cert, C=US, O=MSR_TEST"; var serverCA = MakeCertInternal(serverCaName, serverCaName, true, null, null, 1); var serverCert = MakeCertInternal(serverCaName, serverName, false, serverCA.KeyPair, null, 0); Helpers.WritePEMObject(ToPath(Program.ServerCA), serverCA.Certificate); Helpers.WritePEMObjects(ToPath(Program.ServerChain), new Object[] { serverCA.Certificate, serverCert.Certificate }); //Helpers.WritePEMObject(ToPath("T0_ServerCAKey.PEM", serverCA.KeyPair); Helpers.WritePEMObject(ToPath(Program.ServerCert), serverCert.Certificate); Helpers.WritePEMObject(ToPath(Program.ServerKey), serverCert.KeyPair); // OpenSSL needs a file with the Device CA AND the server CA JoinFiles(Program.DeviceCertChain, Program.ServerCA, Program.DeviceCertChainAndServerCA); // OpenSSL test scripts - // print a cert // openssl x509 -text -in T0_ServerCA.pem // Just verify the client chain // openssl verify -purpose sslclient -CAfile T0_DeviceCertChain.PEM DeviceAliasCert.PEM // Just verify the server chain // openssl verify -purpose sslserver -CAfile T0_ServerCA.PEM T0_ServerCert.PEM // openssl s_client -connect localhost: 5556 - cert T0_AliasCert.PEM - key T0_AliasKey.PEM - CAfile T0_DeviceCertChainAndServerCA.PEM // openssl s_client -connect localhost:5556 -cert T0_AliasCert.PEM -key T0_AliasKey.PEM -CAfile T0_DeviceCertChain.PEM // openssl s_server -cert T0_ServerCert.PEM -key T0_ServerKey.PEM -CAfile T0_DeviceCertChainAndServerCA.PEM -status_verbose -verify 10 -rev -accept 5556 return; }
/// <summary> /// Make a new Alias Cert. If refresh=false, a new DevID and Alias are created. If refresh=true /// then just the Alias is created and re-certified using the stored DevID key. /// </summary> /// <param name="refresh"></param> /// <returns></returns> internal DeviceBundle MakeAliasCert(bool refresh, int fwidSeed) { DateTime now = DateTime.Now; byte[] fwid = Helpers.HashData(new byte[1] { (byte)fwidSeed }, 0, 1); const int keyStrength = 256; CryptoApiRandomGenerator rg = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(rg); KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new ECKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); AsymmetricCipherKeyPair devIdKey = null; if (refresh) { devIdKey = (AsymmetricCipherKeyPair)Helpers.ReadPemObject(ToPath(Program.DeviceIDPrivate)); } else { devIdKey = keyPairGenerator.GenerateKeyPair(); } // test - remove var oids = new List <Object>() { X509Name.UnstructuredName }; var values = new List <Object>() { "ljkljljklkjlkjlkjlkjlkjlkjlkjlkjlkjljklkjlkjlkjlkjljk" }; X509Name name = new X509Name(oids, values); AsymmetricCipherKeyPair aliasKey = keyPairGenerator.GenerateKeyPair(); // make a string name based on DevID public. Note that the authoritative information // is encoded in the RIoT-extension: this is just for quick-and-dirty device identification. var pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(devIdKey.Public); byte[] pubEncoded = pubInfo.GetDerEncoded(); var pubHashed = Helpers.HashData(pubEncoded, 0, pubEncoded.Length); var shortNameBytes = Helpers.CopyArray(pubHashed, 0, 8); var shortNameString = Helpers.Hexify(shortNameBytes); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); var serialNumber = new byte[8]; rg.NextBytes(serialNumber); serialNumber[0] &= 0x7F; certGen.SetSerialNumber(new BigInteger(serialNumber)); // The important name-related stuff is encoded in the RIoT extension certGen.SetIssuerDN(new X509Name($"CN=[I]DevID:{shortNameString}, O=MSR_TEST, C=US")); // test REMOVE //certGen.SetSubjectDN(name); certGen.SetSubjectDN(new X509Name($"CN=[S]DevID:{shortNameString}, O=MSR_TEST, C=US")); certGen.SetNotBefore(now); certGen.SetNotAfter(now + new TimeSpan(365 * 10, 0, 0, 0, 0)); certGen.SetPublicKey(aliasKey.Public); // Add the extensions (todo: not sure about KeyUsage.DigitalSiganture certGen.AddExtension(X509Extensions.ExtendedKeyUsage, true, ExtendedKeyUsage.GetInstance(new DerSequence(KeyPurposeID.IdKPClientAuth))); certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature)); AddRIoTExtension(certGen, fwid, devIdKey); // sign it ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHECDSA", devIdKey.Private, random); var certificate = certGen.Generate(signatureFactory); // and return the bundle DeviceBundle bundle = new DeviceBundle { AliasCert = certificate, DeviceIDPublic = devIdKey.Public, AliasKeyPair = aliasKey }; // Just the AliasCert Helpers.WritePEMObject(ToPath(Program.AliasCert), bundle.AliasCert); // The Alias Key Pair Helpers.WritePEMObject(ToPath(Program.AliasKey), bundle.AliasKeyPair); // The encoded DevID Helpers.WritePEMObject(ToPath(Program.DeviceIDPublic), bundle.DeviceIDPublic); // DeviceIDPrivate (just for the update demo) Helpers.WritePEMObject(ToPath(Program.DeviceIDPrivate), devIdKey.Private); return(bundle); }