Esempio n. 1
0
		public static void Main(
			string[] args)
		{
//			Security.addProvider(new BouncyCastleProvider());

			//
			// personal keys
			//
//			RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
			RsaKeyParameters pubKey = new RsaKeyParameters(false,
				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
				new BigInteger("11", 16));

//			RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
			RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
				new BigInteger("11", 16),
				new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
				new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
				new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
				new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
				new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
				new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));

			//
			// intermediate keys.
			//
//			RSAPublicKeySpec intPubKeySpec = new RSAPublicKeySpec(
			RsaKeyParameters intPubKey = new RsaKeyParameters(false,
				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
				new BigInteger("ffff", 16));


//			RSAPrivateCrtKeySpec intPrivKeySpec = new RSAPrivateCrtKeySpec(
			RsaPrivateCrtKeyParameters intPrivKey = new RsaPrivateCrtKeyParameters(
				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
				new BigInteger("ffff", 16),
				new BigInteger("7deb1b194a85bcfd29cf871411468adbc987650903e3bacc8338c449ca7b32efd39ffc33bc84412fcd7df18d23ce9d7c25ea910b1ae9985373e0273b4dca7f2e0db3b7314056ac67fd277f8f89cf2fd73c34c6ca69f9ba477143d2b0e2445548aa0b4a8473095182631da46844c356f5e5c7522eb54b5a33f11d730ead9c0cff", 16),
				new BigInteger("ef4cede573cea47f83699b814de4302edb60eefe426c52e17bd7870ec7c6b7a24fe55282ebb73775f369157726fcfb988def2b40350bdca9e5b418340288f649", 16),
				new BigInteger("97c7737d1b9a0088c3c7b528539247fd2a1593e7e01cef18848755be82f4a45aa093276cb0cbf118cb41117540a78f3fc471ba5d69f0042274defc9161265721", 16),
				new BigInteger("6c641094e24d172728b8da3c2777e69adfd0839085be7e38c7c4a2dd00b1ae969f2ec9d23e7e37090fcd449a40af0ed463fe1c612d6810d6b4f58b7bfa31eb5f", 16),
				new BigInteger("70b7123e8e69dfa76feb1236d0a686144b00e9232ed52b73847e74ef3af71fb45ccb24261f40d27f98101e230cf27b977a5d5f1f15f6cf48d5cb1da2a3a3b87f", 16),
				new BigInteger("e38f5750d97e270996a286df2e653fd26c242106436f5bab0f4c7a9e654ce02665d5a281f2c412456f2d1fa26586ef04a9adac9004ca7f913162cb28e13bf40d", 16));

			//
			// ca keys
			//
//			RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
			RsaKeyParameters caPubKey = new RsaKeyParameters(false,
				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
				new BigInteger("11", 16));

//			RSAPrivateCrtKeySpec   caPrivKeySpec = new RSAPrivateCrtKeySpec(
			RsaPrivateCrtKeyParameters caPrivKey = new RsaPrivateCrtKeyParameters(
				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
				new BigInteger("11", 16),
				new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
				new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
				new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
				new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
				new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
				new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));



			//
			// set up the keys
			//
//			KeyFactory          fact = KeyFactory.getInstance("RSA", "BC");
//			PrivateKey          caPrivKey = fact.generatePrivate(caPrivKeySpec);
//			PublicKey           caPubKey = fact.generatePublic(caPubKeySpec);
//			PrivateKey          intPrivKey = fact.generatePrivate(intPrivKeySpec);
//			PublicKey           intPubKey = fact.generatePublic(intPubKeySpec);
//			PrivateKey          privKey = fact.generatePrivate(privKeySpec);
//			PublicKey           pubKey = fact.generatePublic(pubKeySpec);

			X509CertificateEntry[] chain = new X509CertificateEntry[3];

			chain[2] = CreateMasterCert(caPubKey, caPrivKey);
			chain[1] = CreateIntermediateCert(intPubKey, caPrivKey, chain[2].Certificate);
			chain[0] = CreateCert(pubKey, intPrivKey, intPubKey);

			//
			// add the friendly name for the private key
			//
//			PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)privKey;
			IDictionary bagAttr = new Hashtable();

			//
			// this is also optional - in the sense that if you leave this
			// out the keystore will add it automatically, note though that
			// for the browser to recognise which certificate the private key
			// is associated with you should at least use the pkcs_9_localKeyId
			// OID and set it to the same as you do for the private key's
			// corresponding certificate.
			//
//			bagAttr.setBagAttribute(
//				PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
//				new DERBMPString("Eric's Key"));
//			bagAttr.setBagAttribute(
//				PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
//				new SubjectKeyIdentifierStructure(pubKey));
			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id,
				new DerBmpString("Eric's Key"));
			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id,
				new SubjectKeyIdentifierStructure(pubKey));

			//
			// store the key and the certificate chain
			//
//			KeyStore store = KeyStore.getInstance("PKCS12", "BC");
//			store.load(null, null);
			Pkcs12Store store = new Pkcs12StoreBuilder().Build();

			//
			// if you haven't set the friendly name and local key id above
			// the name below will be the name of the key
			//
			store.SetKeyEntry("Eric's Key", new AsymmetricKeyEntry(privKey, bagAttr), chain);

//			FileOutputStream fOut = new FileOutputStream("id.p12");
//
//			store.store(fOut, passwd);
			FileStream fOut = File.Create("id.p12");
			store.Save(fOut, passwd, new SecureRandom());
			fOut.Close();
		}
        /// <summary>
        /// Static method used to create a certificate and return as a .net object
        /// </summary>
        public static X509Certificate2 Create(string name, DateTime start, DateTime end, string userPassword, bool addtoStore = false, string exportDirectory = null)
        {
            // generate a key pair using RSA
            var generator = new RsaKeyPairGenerator();

            // keys have to be a minimum of 2048 bits for Azure
            generator.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048));
            AsymmetricCipherKeyPair cerKp = generator.GenerateKeyPair();
            // get a copy of the private key
            AsymmetricKeyParameter privateKey = cerKp.Private;

            // create the CN using the name passed in and create a unique serial number for the cert
            var        certName = new X509Name("CN=" + name);
            BigInteger serialNo = BigInteger.ProbablePrime(120, new Random());

            // start the generator and set CN/DN and serial number and valid period
            var x509Generator = new X509V3CertificateGenerator();

            x509Generator.SetSerialNumber(serialNo);
            x509Generator.SetSubjectDN(certName);
            x509Generator.SetIssuerDN(certName);
            x509Generator.SetNotBefore(start);
            x509Generator.SetNotAfter(end);
            // add the server authentication key usage
            var keyUsage = new KeyUsage(KeyUsage.KeyEncipherment);

            x509Generator.AddExtension(X509Extensions.KeyUsage, false, keyUsage.ToAsn1Object());
            var extendedKeyUsage = new ExtendedKeyUsage(new[] { KeyPurposeID.IdKPServerAuth });

            x509Generator.AddExtension(X509Extensions.ExtendedKeyUsage, true, extendedKeyUsage.ToAsn1Object());
            // algorithm can only be SHA1 ??
            x509Generator.SetSignatureAlgorithm("sha1WithRSA");

            // Set the key pair
            x509Generator.SetPublicKey(cerKp.Public);
            X509Certificate certificate = x509Generator.Generate(cerKp.Private);

            // export the certificate bytes
            byte[] certStream = DotNetUtilities.ToX509Certificate(certificate).Export(X509ContentType.Pkcs12, userPassword);

            // build the key parameter and the certificate entry
            var keyEntry = new AsymmetricKeyEntry(privateKey);
            var entry    = new X509CertificateEntry(certificate);
            // build the PKCS#12 store to encapsulate the certificate
            var builder = new Pkcs12StoreBuilder();

            builder.SetUseDerEncoding(true);
            builder.SetCertAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption);
            builder.SetKeyAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption);
            builder.Build();
            // create a memorystream to hold the output
            var stream = new MemoryStream(10000);
            // create the individual store and set two entries for cert and key
            var store = new Pkcs12Store();

            store.SetCertificateEntry("Created by Fluent Management", entry);
            store.SetKeyEntry("Created by Fluent Management", keyEntry, new[] { entry });
            store.Save(stream, userPassword.ToCharArray(), new SecureRandom());

            // Create the equivalent C# representation
            var cert = new X509Certificate2(stream.GetBuffer(), userPassword, X509KeyStorageFlags.Exportable);

            // set up the PEM writer too
            if (exportDirectory != null)
            {
                var textWriter = new StringWriter();
                var pemWriter  = new PemWriter(textWriter);
                pemWriter.WriteObject(cerKp.Private, "DESEDE", userPassword.ToCharArray(), new SecureRandom());
                pemWriter.Writer.Flush();
                string privateKeyPem = textWriter.ToString();
                using (var writer = new StreamWriter(Path.Combine(exportDirectory, cert.Thumbprint + ".pem")))
                {
                    writer.WriteLine(privateKeyPem);
                }
                // also export the certs - first the .pfx
                byte[] privateKeyBytes = cert.Export(X509ContentType.Pfx, userPassword);
                using (var writer = new FileStream(Path.Combine(exportDirectory, cert.Thumbprint + ".pfx"), FileMode.OpenOrCreate, FileAccess.Write))
                {
                    writer.Write(privateKeyBytes, 0, privateKeyBytes.Length);
                }
                // also export the certs - then the .cer
                byte[] publicKeyBytes = cert.Export(X509ContentType.Cert);
                using (var writer = new FileStream(Path.Combine(exportDirectory, cert.Thumbprint + ".cer"), FileMode.OpenOrCreate, FileAccess.Write))
                {
                    writer.Write(publicKeyBytes, 0, publicKeyBytes.Length);
                }
            }

            // if specified then this add this certificate to the store
            if (addtoStore)
            {
                AddToMyStore(cert);
            }

            return(cert);
        }
Esempio n. 3
0
        private void doTestParams(
            byte[]  ecParameterEncoded,
            bool compress)
        {
//			string keyStorePass = "******";
            Asn1Sequence            seq = (Asn1Sequence)Asn1Object.FromByteArray(ecParameterEncoded);
            X9ECParameters          x9  = new X9ECParameters(seq);
            AsymmetricCipherKeyPair kp  = null;
            bool success = false;

            while (!success)
            {
                IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
//				kpg.Init(new ECParameterSpec(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed()));
                ECDomainParameters ecParams = new ECDomainParameters(
                    x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
                kpg.Init(new ECKeyGenerationParameters(ecParams, new SecureRandom()));
                kp = kpg.GenerateKeyPair();
                // The very old Problem... we need a certificate chain to
                // save a private key...
                ECPublicKeyParameters pubKey = (ECPublicKeyParameters)kp.Public;

                if (!compress)
                {
                    //pubKey.setPointFormat("UNCOMPRESSED");
                    pubKey = SetPublicUncompressed(pubKey);
                }

                byte[] x = pubKey.Q.AffineXCoord.ToBigInteger().ToByteArrayUnsigned();
                byte[] y = pubKey.Q.AffineYCoord.ToBigInteger().ToByteArrayUnsigned();
                if (x.Length == y.Length)
                {
                    success = true;
                }
            }

            // The very old Problem... we need a certificate chain to
            // save a private key...

            X509CertificateEntry[] chain = new X509CertificateEntry[] {
                new X509CertificateEntry(GenerateSelfSignedSoftECCert(kp, compress))
            };

//			KeyStore keyStore = KeyStore.getInstance("BKS");
//			keyStore.load(null, keyStorePass.ToCharArray());
            Pkcs12Store keyStore = new Pkcs12StoreBuilder().Build();

            keyStore.SetCertificateEntry("ECCert", chain[0]);

            ECPrivateKeyParameters privateECKey = (ECPrivateKeyParameters)kp.Private;

            keyStore.SetKeyEntry("ECPrivKey", new AsymmetricKeyEntry(privateECKey), chain);

            // Test ec sign / verify
            ECPublicKeyParameters pub = (ECPublicKeyParameters)kp.Public;

//			string oldPrivateKey = new string(Hex.encode(privateECKey.getEncoded()));
            byte[] oldPrivateKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateECKey).GetDerEncoded();
            string oldPrivateKey      = Hex.ToHexString(oldPrivateKeyBytes);

//			string oldPublicKey = new string(Hex.encode(pub.getEncoded()));
            byte[] oldPublicKeyBytes      = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub).GetDerEncoded();
            string oldPublicKey           = Hex.ToHexString(oldPublicKeyBytes);
            ECPrivateKeyParameters newKey = (ECPrivateKeyParameters)
                                            keyStore.GetKey("ECPrivKey").Key;
            ECPublicKeyParameters newPubKey = (ECPublicKeyParameters)
                                              keyStore.GetCertificate("ECCert").Certificate.GetPublicKey();

            if (!compress)
            {
                // TODO Private key compression?
                //newKey.setPointFormat("UNCOMPRESSED");
                //newPubKey.setPointFormat("UNCOMPRESSED");
                newPubKey = SetPublicUncompressed(newPubKey);
            }

//			string newPrivateKey = new string(Hex.encode(newKey.getEncoded()));
            byte[] newPrivateKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(newKey).GetDerEncoded();
            string newPrivateKey      = Hex.ToHexString(newPrivateKeyBytes);

//			string newPublicKey = new string(Hex.encode(newPubKey.getEncoded()));
            byte[] newPublicKeyBytes = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(newPubKey).GetDerEncoded();
            string newPublicKey      = Hex.ToHexString(newPublicKeyBytes);

            if (!oldPrivateKey.Equals(newPrivateKey))
//			if (!privateECKey.Equals(newKey))
            {
                Fail("failed private key comparison");
            }

            if (!oldPublicKey.Equals(newPublicKey))
//			if (!pub.Equals(newPubKey))
            {
                Fail("failed public key comparison");
            }
        }
Esempio n. 4
0
        public void Save(
            Stream stream,
            char[] password,
            SecureRandom random)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (random == null)
            {
                throw new ArgumentNullException("random");
            }

            //
            // handle the keys
            //
            Asn1EncodableVector keyBags = new Asn1EncodableVector();

            foreach (string name in keys.Keys)
            {
                byte[] kSalt = new byte[SaltSize];
                random.NextBytes(kSalt);

                AsymmetricKeyEntry privKey = (AsymmetricKeyEntry)keys[name];

                DerObjectIdentifier bagOid;
                Asn1Encodable       bagData;

                if (password == null)
                {
                    bagOid  = PkcsObjectIdentifiers.KeyBag;
                    bagData = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey.Key);
                }
                else
                {
                    bagOid  = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
                    bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
                        keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
                }

                Asn1EncodableVector kName = new Asn1EncodableVector();

                foreach (string oid in privKey.BagAttributeKeys)
                {
                    Asn1Encodable entry = privKey[oid];

                    // NB: Ignore any existing FriendlyName
                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
                    {
                        continue;
                    }

                    kName.Add(
                        new DerSequence(
                            new DerObjectIdentifier(oid),
                            new DerSet(entry)));
                }

                //
                // make sure we are using the local alias on store
                //
                // NB: We always set the FriendlyName based on 'name'
                //if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
                {
                    kName.Add(
                        new DerSequence(
                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
                            new DerSet(new DerBmpString(name))));
                }

                //
                // make sure we have a local key-id
                //
                if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
                {
                    X509CertificateEntry   ct           = GetCertificate(name);
                    AsymmetricKeyParameter pubKey       = ct.Certificate.GetPublicKey();
                    SubjectKeyIdentifier   subjectKeyID = CreateSubjectKeyID(pubKey);

                    kName.Add(
                        new DerSequence(
                            PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
                            new DerSet(subjectKeyID)));
                }

                keyBags.Add(new SafeBag(bagOid, bagData.ToAsn1Object(), new DerSet(kName)));
            }

            byte[]      keyBagsEncoding = new DerSequence(keyBags).GetDerEncoded();
            ContentInfo keysInfo        = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(keyBagsEncoding));

            //
            // certificate processing
            //
            byte[] cSalt = new byte[SaltSize];

            random.NextBytes(cSalt);

            Asn1EncodableVector certBags = new Asn1EncodableVector();
            Pkcs12PbeParams     cParams  = new Pkcs12PbeParams(cSalt, MinIterations);
            AlgorithmIdentifier cAlgId   = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
            ISet doneCerts = new HashSet();

            foreach (string name in keys.Keys)
            {
                X509CertificateEntry certEntry = GetCertificate(name);
                CertBag cBag = new CertBag(
                    PkcsObjectIdentifiers.X509Certificate,
                    new DerOctetString(certEntry.Certificate.GetEncoded()));

                Asn1EncodableVector fName = new Asn1EncodableVector();

                foreach (string oid in certEntry.BagAttributeKeys)
                {
                    Asn1Encodable entry = certEntry[oid];

                    // NB: Ignore any existing FriendlyName
                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
                    {
                        continue;
                    }

                    fName.Add(
                        new DerSequence(
                            new DerObjectIdentifier(oid),
                            new DerSet(entry)));
                }

                //
                // make sure we are using the local alias on store
                //
                // NB: We always set the FriendlyName based on 'name'
                //if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
                {
                    fName.Add(
                        new DerSequence(
                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
                            new DerSet(new DerBmpString(name))));
                }

                //
                // make sure we have a local key-id
                //
                if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
                {
                    AsymmetricKeyParameter pubKey       = certEntry.Certificate.GetPublicKey();
                    SubjectKeyIdentifier   subjectKeyID = CreateSubjectKeyID(pubKey);

                    fName.Add(
                        new DerSequence(
                            PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
                            new DerSet(subjectKeyID)));
                }

                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));

                doneCerts.Add(certEntry.Certificate);
            }

            foreach (string certId in certs.Keys)
            {
                X509CertificateEntry cert = (X509CertificateEntry)certs[certId];

                if (keys[certId] != null)
                {
                    continue;
                }

                CertBag cBag = new CertBag(
                    PkcsObjectIdentifiers.X509Certificate,
                    new DerOctetString(cert.Certificate.GetEncoded()));

                Asn1EncodableVector fName = new Asn1EncodableVector();

                foreach (string oid in cert.BagAttributeKeys)
                {
                    // a certificate not immediately linked to a key doesn't require
                    // a localKeyID and will confuse some PKCS12 implementations.
                    //
                    // If we find one, we'll prune it out.
                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id))
                    {
                        continue;
                    }

                    Asn1Encodable entry = cert[oid];

                    // NB: Ignore any existing FriendlyName
                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
                    {
                        continue;
                    }

                    fName.Add(
                        new DerSequence(
                            new DerObjectIdentifier(oid),
                            new DerSet(entry)));
                }

                //
                // make sure we are using the local alias on store
                //
                // NB: We always set the FriendlyName based on 'certId'
                //if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
                {
                    fName.Add(
                        new DerSequence(
                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
                            new DerSet(new DerBmpString(certId))));
                }

                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));

                doneCerts.Add(cert.Certificate);
            }

            foreach (CertId certId in chainCerts.Keys)
            {
                X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];

                if (doneCerts.Contains(cert.Certificate))
                {
                    continue;
                }

                CertBag cBag = new CertBag(
                    PkcsObjectIdentifiers.X509Certificate,
                    new DerOctetString(cert.Certificate.GetEncoded()));

                Asn1EncodableVector fName = new Asn1EncodableVector();

                foreach (string oid in cert.BagAttributeKeys)
                {
                    // a certificate not immediately linked to a key doesn't require
                    // a localKeyID and will confuse some PKCS12 implementations.
                    //
                    // If we find one, we'll prune it out.
                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id))
                    {
                        continue;
                    }

                    fName.Add(
                        new DerSequence(
                            new DerObjectIdentifier(oid),
                            new DerSet(cert[oid])));
                }

                certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
            }

            byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();

            ContentInfo certsInfo;

            if (password == null)
            {
                certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
            }
            else
            {
                byte[]        certBytes = CryptPbeData(true, cAlgId, password, false, certBagsEncoding);
                EncryptedData cInfo     = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
                certsInfo = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object());
            }

            ContentInfo[] info = new ContentInfo[] { keysInfo, certsInfo };

            byte[] data = new AuthenticatedSafe(info).GetEncoded(
                useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);

            ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data));

            //
            // create the mac
            //
            MacData macData = null;

            if (password != null)
            {
                byte[] mSalt = new byte[20];
                random.NextBytes(mSalt);

                byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
                                             mSalt, MinIterations, password, false, data);

                AlgorithmIdentifier algId = new AlgorithmIdentifier(
                    OiwObjectIdentifiers.IdSha1, DerNull.Instance);
                DigestInfo dInfo = new DigestInfo(algId, mac);

                macData = new MacData(dInfo, mSalt, MinIterations);
            }

            //
            // output the Pfx
            //
            Pfx pfx = new Pfx(mainInfo, macData);

            DerOutputStream derOut;

            if (useDerEncoding)
            {
                derOut = new DerOutputStream(stream);
            }
            else
            {
                derOut = new BerOutputStream(stream);
            }

            derOut.WriteObject(pfx);
        }
Esempio n. 5
0
        // Only the ctor should be calling with isAuthority = true
        // if isAuthority, value for isMachineCert doesn't matter
        private X509CertificateContainer CreateCertificate(bool isAuthority, bool isMachineCert, X509Certificate signingCertificate, CertificateCreationSettings certificateCreationSettings)
        {
            if (certificateCreationSettings == null)
            {
                if (isAuthority)
                {
                    certificateCreationSettings = new CertificateCreationSettings();
                }
                else
                {
                    throw new Exception("Parameter certificateCreationSettings cannot be null when isAuthority is false");
                }
            }

            // Set to default cert creation settings if not set
            if (certificateCreationSettings.ValidityNotBefore == default(DateTime))
            {
                certificateCreationSettings.ValidityNotBefore = _defaultValidityNotBefore;
            }
            if (certificateCreationSettings.ValidityNotAfter == default(DateTime))
            {
                certificateCreationSettings.ValidityNotAfter = _defaultValidityNotAfter;
            }

            if (!isAuthority ^ (signingCertificate != null))
            {
                throw new ArgumentException("Either isAuthority == true or signingCertificate is not null");
            }
            string subject = certificateCreationSettings.Subject;

            // If certificateCreationSettings.SubjectAlternativeNames == null, then we should add exactly one SubjectAlternativeName == Subject
            // so that the default certificate generated is compatible with mainline scenarios
            // However, if certificateCreationSettings.SubjectAlternativeNames == string[0], then allow this as this is a legit scenario we want to test out
            if (certificateCreationSettings.SubjectAlternativeNames == null)
            {
                certificateCreationSettings.SubjectAlternativeNames = new string[1] {
                    subject
                };
            }

            string[] subjectAlternativeNames = certificateCreationSettings.SubjectAlternativeNames;

            if (!isAuthority && string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentException("Certificate Subject must not be an empty string or only whitespace", "creationSettings.Subject");
            }

            EnsureInitialized();

            s_certGenerator.Reset();

            // Tag on the generation time to prevent caching of the cert CRL in Linux
            X509Name authorityX509Name = CreateX509Name(string.Format("{0} {1}", _authorityCanonicalName, DateTime.Now.ToString("s")));
            var      serialNum         = new BigInteger(64 /*sizeInBits*/, _random).Abs();

            var keyPair = isAuthority ? _authorityKeyPair : _keyPairGenerator.GenerateKeyPair();

            if (isAuthority)
            {
                s_certGenerator.SetIssuerDN(authorityX509Name);
                s_certGenerator.SetSubjectDN(authorityX509Name);

                var authorityKeyIdentifier = new AuthorityKeyIdentifier(
                    SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_authorityKeyPair.Public),
                    new GeneralNames(new GeneralName(authorityX509Name)),
                    serialNum);

                s_certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, authorityKeyIdentifier);
                s_certGenerator.AddExtension(X509Extensions.KeyUsage, false, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyCertSign | X509KeyUsage.KeyEncipherment | X509KeyUsage.CrlSign));
            }
            else
            {
                X509Name subjectName = CreateX509Name(subject);
                s_certGenerator.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(signingCertificate));
                s_certGenerator.SetSubjectDN(subjectName);

                s_certGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(_authorityKeyPair.Public));
                s_certGenerator.AddExtension(X509Extensions.KeyUsage, false, new KeyUsage(X509KeyUsage.DigitalSignature | X509KeyUsage.KeyAgreement | X509KeyUsage.KeyEncipherment));
            }

            s_certGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keyPair.Public));

            s_certGenerator.SetSerialNumber(serialNum);
            s_certGenerator.SetNotBefore(certificateCreationSettings.ValidityNotBefore);
            s_certGenerator.SetNotAfter(certificateCreationSettings.ValidityNotAfter);
            s_certGenerator.SetPublicKey(keyPair.Public);

            s_certGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(isAuthority));
            if (certificateCreationSettings.EKU == null || certificateCreationSettings.EKU.Count == 0)
            {
                s_certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth));
            }
            else
            {
                s_certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(certificateCreationSettings.EKU));
            }

            if (!isAuthority)
            {
                if (isMachineCert)
                {
                    List <Asn1Encodable> subjectAlternativeNamesAsAsn1EncodableList = new List <Asn1Encodable>();

                    // All endpoints should also be in the Subject Alt Names
                    for (int i = 0; i < subjectAlternativeNames.Length; i++)
                    {
                        if (!string.IsNullOrWhiteSpace(subjectAlternativeNames[i]))
                        {
                            // Machine certs can have additional DNS names
                            subjectAlternativeNamesAsAsn1EncodableList.Add(new GeneralName(GeneralName.DnsName, subjectAlternativeNames[i]));
                        }
                    }

                    s_certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNamesAsAsn1EncodableList.ToArray()));
                }
                else
                {
                    if (subjectAlternativeNames.Length > 1)
                    {
                        var subjectAlternativeNamesAsAsn1EncodableList = new Asn1EncodableVector();

                        // Only add a SAN for the user if there are any
                        for (int i = 1; i < subjectAlternativeNames.Length; i++)
                        {
                            if (!string.IsNullOrWhiteSpace(subjectAlternativeNames[i]))
                            {
                                Asn1EncodableVector otherNames = new Asn1EncodableVector();
                                otherNames.Add(new DerObjectIdentifier(_upnObjectId));
                                otherNames.Add(new DerTaggedObject(true, 0, new DerUtf8String(subjectAlternativeNames[i])));

                                Asn1Object genName = new DerTaggedObject(false, 0, new DerSequence(otherNames));

                                subjectAlternativeNamesAsAsn1EncodableList.Add(genName);
                            }
                        }
                        s_certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new DerSequence(subjectAlternativeNamesAsAsn1EncodableList));
                    }
                }
            }

            if (isAuthority || certificateCreationSettings.IncludeCrlDistributionPoint)
            {
                var crlDistributionPoints = new DistributionPoint[1]
                {
                    new DistributionPoint(
                        new DistributionPointName(
                            new GeneralNames(
                                new GeneralName(
                                    GeneralName.UniformResourceIdentifier, string.Format("{0}", _crlUri, serialNum.ToString(radix: 16))))),
                        null,
                        null)
                };
                var revocationListExtension = new CrlDistPoint(crlDistributionPoints);
                s_certGenerator.AddExtension(X509Extensions.CrlDistributionPoints, false, revocationListExtension);
            }

            ISignatureFactory signatureFactory = new Asn1SignatureFactory(_signatureAlthorithm, _authorityKeyPair.Private, _random);
            X509Certificate   cert             = s_certGenerator.Generate(signatureFactory);

            switch (certificateCreationSettings.ValidityType)
            {
            case CertificateValidityType.Revoked:
                RevokeCertificateBySerialNumber(serialNum.ToString(radix: 16));
                break;

            case CertificateValidityType.Expired:
                break;

            default:
                EnsureCertificateIsValid(cert);
                break;
            }

            // For now, given that we don't know what format to return it in, preserve the formats so we have
            // the flexibility to do what we need to

            X509CertificateContainer container = new X509CertificateContainer();

            X509CertificateEntry[] chain = new X509CertificateEntry[1];
            chain[0] = new X509CertificateEntry(cert);

            Pkcs12Store store = new Pkcs12StoreBuilder().Build();

            store.SetKeyEntry(
                certificateCreationSettings.FriendlyName != null ? certificateCreationSettings.FriendlyName : string.Empty,
                new AsymmetricKeyEntry(keyPair.Private),
                chain);

            using (MemoryStream stream = new MemoryStream())
            {
                store.Save(stream, _password.ToCharArray(), _random);
                container.Pfx = stream.ToArray();
            }

            X509Certificate2 outputCert;

            if (isAuthority)
            {
                // don't hand out the private key for the cert when it's the authority
                outputCert = new X509Certificate2(cert.GetEncoded());
            }
            else
            {
                // Otherwise, allow encode with the private key. note that X509Certificate2.RawData will not provide the private key
                // you will have to re-export this cert if needed
                outputCert = new X509Certificate2(container.Pfx, _password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
            }

            container.Subject             = subject;
            container.InternalCertificate = cert;
            container.Certificate         = outputCert;
            container.Thumbprint          = outputCert.Thumbprint;

            Trace.WriteLine("[CertificateGenerator] generated a certificate:");
            Trace.WriteLine(string.Format("    {0} = {1}", "isAuthority", isAuthority));
            if (!isAuthority)
            {
                Trace.WriteLine(string.Format("    {0} = {1}", "Signed by", signingCertificate.SubjectDN));
                Trace.WriteLine(string.Format("    {0} = {1}", "Subject (CN) ", subject));
                Trace.WriteLine(string.Format("    {0} = {1}", "Subject Alt names ", string.Join(", ", subjectAlternativeNames)));
                Trace.WriteLine(string.Format("    {0} = {1}", "Friendly Name ", certificateCreationSettings.FriendlyName));
            }
            Trace.WriteLine(string.Format("    {0} = {1}", "HasPrivateKey:", outputCert.HasPrivateKey));
            Trace.WriteLine(string.Format("    {0} = {1}", "Thumbprint", outputCert.Thumbprint));
            Trace.WriteLine(string.Format("    {0} = {1}", "CertificateValidityType", certificateCreationSettings.ValidityType));

            return(container);
        }
Esempio n. 6
0
        public void Load(
            Stream input,
            char[] password)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            Asn1Sequence obj             = (Asn1Sequence)Asn1Object.FromStream(input);
            Pfx          bag             = new Pfx(obj);
            ContentInfo  info            = bag.AuthSafe;
            bool         wrongPkcs12Zero = false;

            if (password != null && bag.MacData != null) // check the mac code
            {
                MacData             mData = bag.MacData;
                DigestInfo          dInfo = mData.Mac;
                AlgorithmIdentifier algId = dInfo.AlgorithmID;
                byte[] salt    = mData.GetSalt();
                int    itCount = mData.IterationCount.IntValue;

                byte[] data = ((Asn1OctetString)info.Content).GetOctets();

                byte[] mac = CalculatePbeMac(algId.Algorithm, salt, itCount, password, false, data);
                byte[] dig = dInfo.GetDigest();

                if (!Arrays.ConstantTimeAreEqual(mac, dig))
                {
                    if (password.Length > 0)
                    {
                        throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
                    }

                    // Try with incorrect zero length password
                    mac = CalculatePbeMac(algId.Algorithm, salt, itCount, password, true, data);

                    if (!Arrays.ConstantTimeAreEqual(mac, dig))
                    {
                        throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
                    }

                    wrongPkcs12Zero = true;
                }
            }

            keys.Clear();
            localIds.Clear();
            unmarkedKeyEntry = null;

            IList certBags = Platform.CreateArrayList();

            if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
            {
                byte[]            octs     = ((Asn1OctetString)info.Content).GetOctets();
                AuthenticatedSafe authSafe = new AuthenticatedSafe(
                    (Asn1Sequence)Asn1OctetString.FromByteArray(octs));
                ContentInfo[] cis = authSafe.GetContentInfo();

                foreach (ContentInfo ci in cis)
                {
                    DerObjectIdentifier oid = ci.ContentType;

                    byte[] octets = null;
                    if (oid.Equals(PkcsObjectIdentifiers.Data))
                    {
                        octets = ((Asn1OctetString)ci.Content).GetOctets();
                    }
                    else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
                    {
                        if (password != null)
                        {
                            EncryptedData d = EncryptedData.GetInstance(ci.Content);
                            octets = CryptPbeData(false, d.EncryptionAlgorithm,
                                                  password, wrongPkcs12Zero, d.Content.GetOctets());
                        }
                    }
                    else
                    {
                        // TODO Other data types
                    }

                    if (octets != null)
                    {
                        Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(octets);

                        foreach (Asn1Sequence subSeq in seq)
                        {
                            SafeBag b = new SafeBag(subSeq);

                            if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
                            {
                                certBags.Add(b);
                            }
                            else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
                            {
                                LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo.GetInstance(b.BagValue),
                                                        b.BagAttributes, password, wrongPkcs12Zero);
                            }
                            else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
                            {
                                LoadKeyBag(PrivateKeyInfo.GetInstance(b.BagValue), b.BagAttributes);
                            }
                            else
                            {
                                // TODO Other bag types
                            }
                        }
                    }
                }
            }

            certs.Clear();
            chainCerts.Clear();
            keyCerts.Clear();

            foreach (SafeBag b in certBags)
            {
                CertBag         certBag = new CertBag((Asn1Sequence)b.BagValue);
                byte[]          octets  = ((Asn1OctetString)certBag.CertValue).GetOctets();
                X509Certificate cert    = new X509CertificateParser().ReadCertificate(octets);

                //
                // set the attributes
                //
                IDictionary     attributes = Platform.CreateHashtable();
                Asn1OctetString localId    = null;
                string          alias      = null;

                if (b.BagAttributes != null)
                {
                    foreach (Asn1Sequence sq in b.BagAttributes)
                    {
                        DerObjectIdentifier aOid    = DerObjectIdentifier.GetInstance(sq[0]);
                        Asn1Set             attrSet = Asn1Set.GetInstance(sq[1]);

                        if (attrSet.Count > 0)
                        {
                            // TODO We should be adding all attributes in the set
                            Asn1Encodable attr = attrSet[0];

                            // TODO We might want to "merge" attribute sets with
                            // the same OID - currently, differing values give an error
                            if (attributes.Contains(aOid.Id))
                            {
                                // OK, but the value has to be the same
                                if (!attributes[aOid.Id].Equals(attr))
                                {
                                    //throw new IOException("attempt to add existing attribute with different value");
                                }
                            }
                            else
                            {
                                attributes.Add(aOid.Id, attr);
                            }

                            if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
                            {
                                alias = ((DerBmpString)attr).GetString();
                            }
                            else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
                            {
                                localId = (Asn1OctetString)attr;
                            }
                        }
                    }
                }

                CertId certId = new CertId(cert.GetPublicKey());
                X509CertificateEntry certEntry = new X509CertificateEntry(cert, attributes);

                chainCerts[certId] = certEntry;

                if (unmarkedKeyEntry != null)
                {
                    if (keyCerts.Count == 0)
                    {
                        string name = Hex.ToHexString(certId.Id);

                        keyCerts[name] = certEntry;
                        keys[name]     = unmarkedKeyEntry;
                    }
                    else
                    {
                        keys["unmarked"] = unmarkedKeyEntry;
                    }
                }
                else
                {
                    if (localId != null)
                    {
                        string name = Hex.ToHexString(localId.GetOctets());

                        keyCerts[name] = certEntry;
                    }

                    if (alias != null)
                    {
                        // TODO There may have been more than one alias
                        certs[alias] = certEntry;
                    }
                }
            }
        }
Esempio n. 7
0
        public X509CertificateEntry[] GetCertificateChain(
            string alias)
        {
            if (alias == null)
            {
                throw new ArgumentNullException("alias");
            }

            if (!IsKeyEntry(alias))
            {
                return(null);
            }

            X509CertificateEntry c = GetCertificate(alias);

            if (c != null)
            {
                IList cs = Platform.CreateArrayList();

                while (c != null)
                {
                    X509Certificate      x509c = c.Certificate;
                    X509CertificateEntry nextC = null;

                    Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
                    if (ext != null)
                    {
                        AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance(
                            Asn1Object.FromByteArray(ext.GetOctets()));

                        if (id.GetKeyIdentifier() != null)
                        {
                            nextC = (X509CertificateEntry)chainCerts[new CertId(id.GetKeyIdentifier())];
                        }
                    }

                    if (nextC == null)
                    {
                        //
                        // no authority key id, try the Issuer DN
                        //
                        X509Name i = x509c.IssuerDN;
                        X509Name s = x509c.SubjectDN;

                        if (!i.Equivalent(s))
                        {
                            foreach (CertId certId in chainCerts.Keys)
                            {
                                X509CertificateEntry x509CertEntry = (X509CertificateEntry)chainCerts[certId];

                                X509Certificate crt = x509CertEntry.Certificate;

                                X509Name sub = crt.SubjectDN;
                                if (sub.Equivalent(i))
                                {
                                    try
                                    {
                                        x509c.Verify(crt.GetPublicKey());

                                        nextC = x509CertEntry;
                                        break;
                                    }
                                    catch (InvalidKeyException)
                                    {
                                        // TODO What if it doesn't verify?
                                    }
                                }
                            }
                        }
                    }

                    cs.Add(c);
                    if (nextC != c) // self signed - end of the chain
                    {
                        c = nextC;
                    }
                    else
                    {
                        c = null;
                    }
                }

                X509CertificateEntry[] result = new X509CertificateEntry[cs.Count];
                for (int i = 0; i < cs.Count; ++i)
                {
                    result[i] = (X509CertificateEntry)cs[i];
                }
                return(result);
            }

            return(null);
        }
    /// <summary>
    /// Creates a self signed application instance certificate.
    /// </summary>
    /// <param name="storeType">Type of certificate store (Directory) <see cref="CertificateStoreType"/>.</param>
    /// <param name="storePath">The store path (syntax depends on storeType).</param>
    /// <param name="password">The password to use to protect the certificate.</param>
    /// <param name="applicationUri">The application uri (created if not specified).</param>
    /// <param name="applicationName">Name of the application (optional if subjectName is specified).</param>
    /// <param name="subjectName">The subject used to create the certificate (optional if applicationName is specified).</param>
    /// <param name="domainNames">The domain names that can be used to access the server machine (defaults to local computer name if not specified).</param>
    /// <param name="keySize">Size of the key (1024, 2048 or 4096).</param>
    /// <param name="startTime">The start time.</param>
    /// <param name="lifetimeInMonths">The lifetime of the key in months.</param>
    /// <param name="hashSizeInBits">The hash size in bits.</param>
    /// <param name="isCA">if set to <c>true</c> then a CA certificate is created.</param>
    /// <param name="issuerCAKeyCert">The CA cert with the CA private key.</param>
    /// <returns>The certificate with a private key.</returns>
    public static X509Certificate2 CreateCertificate(
        string storeType,
        string storePath,
        string password,
        string applicationUri,
        string applicationName,
        string subjectName,
        IList <String> domainNames,
        ushort keySize,
        DateTime startTime,
        ushort lifetimeInMonths,
        ushort hashSizeInBits,
        bool isCA,
        X509Certificate2 issuerCAKeyCert)
    {
        if (issuerCAKeyCert != null)
        {
            if (!issuerCAKeyCert.HasPrivateKey)
            {
                throw new NotSupportedException("Cannot sign with a CA certificate without a private key.");
            }

            throw new NotSupportedException("Signing with an issuer CA certificate is currently unsupported.");
        }

        // set default values.
        X509Name subjectDN = SetSuitableDefaults(
            ref applicationUri,
            ref applicationName,
            ref subjectName,
            ref domainNames,
            ref keySize,
            ref lifetimeInMonths,
            isCA);

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            // cert generators
            SecureRandom random           = new SecureRandom(cfrg);
            X509V3CertificateGenerator cg = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            cg.SetSerialNumber(serialNumber);

            // self signed
            X509Name issuerDN = subjectDN;
            cg.SetIssuerDN(issuerDN);
            cg.SetSubjectDN(subjectDN);

            // valid for
            cg.SetNotBefore(startTime);
            cg.SetNotAfter(startTime.AddMonths(lifetimeInMonths));

            // Private/Public Key
            AsymmetricCipherKeyPair subjectKeyPair;
            var keyGenerationParameters = new KeyGenerationParameters(random, keySize);
            var keyPairGenerator        = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);
            subjectKeyPair = keyPairGenerator.GenerateKeyPair();
            cg.SetPublicKey(subjectKeyPair.Public);

            // add extensions
            // Subject key identifier
            cg.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, false,
                            new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public)));

            // Basic constraints
            cg.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCA));

            // Authority Key identifier
            var issuerKeyPair      = subjectKeyPair;
            var issuerSerialNumber = serialNumber;
            cg.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false,
                            new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public),
                                                       new GeneralNames(new GeneralName(issuerDN)), issuerSerialNumber));

            if (!isCA)
            {
                // Key usage
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.DataEncipherment | KeyUsage.DigitalSignature |
                                             KeyUsage.NonRepudiation | KeyUsage.KeyCertSign | KeyUsage.KeyEncipherment));

                // Extended Key usage
                cg.AddExtension(X509Extensions.ExtendedKeyUsage, true,
                                new ExtendedKeyUsage(new List <DerObjectIdentifier>()
                {
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.1"), // server auth
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.2"), // client auth
                }));

                // subject alternate name
                cg.AddExtension(X509Extensions.SubjectAlternativeName, false,
                                new GeneralNames(new GeneralName[] {
                    new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri),
                    new GeneralName(GeneralName.DnsName, domainNames[0])
                }));
            }
            else
            {
                // Key usage CA
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.CrlSign | KeyUsage.DigitalSignature | KeyUsage.KeyCertSign));
            }

            // sign certificate
            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory((hashSizeInBits < 256) ? "SHA1WITHRSA" : "SHA256WITHRSA", subjectKeyPair.Private, random);
            Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

            // create pkcs12 store for cert and private key
            X509Certificate2 certificate = null;
            using (MemoryStream pfxData = new MemoryStream())
            {
                Pkcs12Store            pkcsStore = new Pkcs12StoreBuilder().Build();
                X509CertificateEntry[] chain     = new X509CertificateEntry[1];
                string passcode = Guid.NewGuid().ToString();
                chain[0] = new X509CertificateEntry(x509);
                pkcsStore.SetKeyEntry(applicationName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain);
                pkcsStore.Save(pfxData, passcode.ToCharArray(), random);

                // merge into X509Certificate2
                certificate = CreateCertificateFromPKCS12(pfxData.ToArray(), passcode);
            }

            Utils.Trace(Utils.TraceMasks.Security, "Created new certificate: {0}", certificate.Thumbprint);

            // add cert to the store.
            if (!String.IsNullOrEmpty(storePath))
            {
                ICertificateStore store = null;
                if (storeType == CertificateStoreType.X509Store)
                {
                    store = new X509CertificateStore();
                }
                else if (storeType == CertificateStoreType.Directory)
                {
                    store = new DirectoryCertificateStore();
                }
                else
                {
                    throw new ArgumentException("Invalid store type");
                }

                store.Open(storePath);
                store.Add(certificate, password);
                store.Close();
                store.Dispose();
            }

            // note: this cert has a private key!
            return(certificate);
        }
    }
Esempio n. 9
0
        public static void Write(string name, string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new ArgumentException("Token not found in X509Store and no new token provided!");
            }

            SecureRandom            random = new SecureRandom();
            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, 2048);
            RsaKeyPairGenerator     keyPairGenerator        = new RsaKeyPairGenerator();

            keyPairGenerator.Init(keyGenerationParameters);
            AsymmetricCipherKeyPair keys = keyPairGenerator.GenerateKeyPair();

            ArrayList nameOids = new ArrayList();

            nameOids.Add(X509Name.CN);
            ArrayList nameValues = new ArrayList();

            nameValues.Add(name);
            X509Name subjectDN = new X509Name(nameOids, nameValues);
            X509Name issuerDN  = subjectDN;

            X509V3CertificateGenerator cg = new X509V3CertificateGenerator();

            cg.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random));
            cg.SetIssuerDN(issuerDN);
            cg.SetSubjectDN(subjectDN);
            cg.SetNotBefore(DateTime.Now);
            cg.SetNotAfter(DateTime.Now.AddMonths(12));
            cg.SetPublicKey(keys.Public);

            // encrypt the token with the public key so only the owner of the assoc. private key can decrypt it and
            // "hide" it in the instruction code cert extension
            RSA              rsa       = RSA.Create();
            RSAParameters    rsaParams = new RSAParameters();
            RsaKeyParameters keyParams = (RsaKeyParameters)keys.Public;

            rsaParams.Modulus = new byte[keyParams.Modulus.ToByteArrayUnsigned().Length];
            keyParams.Modulus.ToByteArrayUnsigned().CopyTo(rsaParams.Modulus, 0);

            rsaParams.Exponent = new byte[keyParams.Exponent.ToByteArrayUnsigned().Length];
            keyParams.Exponent.ToByteArrayUnsigned().CopyTo(rsaParams.Exponent, 0);

            rsa.ImportParameters(rsaParams);
            if (rsa != null)
            {
                byte[] bytes = rsa.Encrypt(Encoding.ASCII.GetBytes(connectionString), RSAEncryptionPadding.OaepSHA1);
                if (bytes != null)
                {
                    cg.AddExtension(X509Extensions.InstructionCode, false, bytes);
                }
                else
                {
                    rsa.Dispose();
                    throw new CryptographicException("Could not encrypt IoTHub security token using generated public key!");
                }
            }
            rsa.Dispose();

            // sign the cert with the private key
            ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keys.Private, random);

            Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

            // create a PKCS12 store for the cert and its private key
            X509Certificate2 certificate = null;

            using (MemoryStream pfxData = new MemoryStream())
            {
                Pkcs12Store            pkcsStore = new Pkcs12StoreBuilder().Build();
                X509CertificateEntry[] chain     = new X509CertificateEntry[1];
                string passcode = "passcode";
                chain[0] = new X509CertificateEntry(x509);
                pkcsStore.SetKeyEntry(name, new AsymmetricKeyEntry(keys.Private), chain);
                pkcsStore.Save(pfxData, passcode.ToCharArray(), random);

                // create X509Certificate2 object from PKCS12 file
                certificate = CreateCertificateFromPKCS12(pfxData.ToArray(), passcode);

                // Add to X509Store
                using (X509Store store = new X509Store("IoTHub", StoreLocation.CurrentUser))
                {
                    store.Open(OpenFlags.ReadWrite);

                    // remove any existing cert with our name from the store
                    foreach (X509Certificate2 cert in store.Certificates)
                    {
                        if (cert.SubjectName.Decode(X500DistinguishedNameFlags.None | X500DistinguishedNameFlags.DoNotUseQuotes).Equals("CN=" + name, StringComparison.OrdinalIgnoreCase))
                        {
                            store.Remove(cert);
                        }
                    }

                    // add new one
                    store.Add(certificate);
                }
            }
        }
Esempio n. 10
0
        //public static string CreatePassword(string origionalPassword, int iterationCount)
        //{
        //    var sha1 = new SHA1Managed();
        //    Rfc2898DeriveBytes generateBytes = new Rfc2898DeriveBytes(origionalPassword, sha1.ComputeHash(Encoding.Unicode.GetBytes(origionalPassword)), iterationCount);
        //    return Convert.ToBase64String(generateBytes.GetBytes(32)).Substring(0, 30);
        //}

        //public static X509Certificate2 Create(string issuer, string[] subjectNames, int strength)
        //{
        //    var cert = GenerateSelfSignedCertificate(issuer);

        //    //add CA cert to store
        //    addCertToStore(cert, StoreName.My, StoreLocation.CurrentUser);
        //    return cert;
        //}

        /// <summary>
        /// Creates a certificate authority certificate.
        /// </summary>
        /// <returns></returns>
        public static X509Certificate2 GenerateSelfSignedCertificate(string subjectDirName, DateTime startDate, DateTime endDate, short signatureBits, int keyStrength)
        {
            string signatureAlgorithm;

            switch (signatureBits)
            {
            case 160:
                signatureAlgorithm = "SHA1withRSA";
                break;

            case 224:
                signatureAlgorithm = "SHA224withRSA";
                break;

            case 256:
                signatureAlgorithm = "SHA256withRSA";
                break;

            case 384:
                signatureAlgorithm = "SHA384withRSA";
                break;

            case 512:
                signatureAlgorithm = "SHA512withRSA";
                break;

            default:
                throw new ArgumentException("Invalid signature bit size.", "signatureBits");
            }

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom             random          = new SecureRandom(randomGenerator);

            // Generate public/private keys.
            AsymmetricCipherKeyPair encryptionKeys;

            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
            RsaKeyPairGenerator     keyPairGenerator        = new RsaKeyPairGenerator();

            keyPairGenerator.Init(keyGenerationParameters);
            encryptionKeys = keyPairGenerator.GenerateKeyPair();

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random));
            certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
            certificateGenerator.SetIssuerDN(new X509Name(subjectDirName));
            certificateGenerator.SetSubjectDN(new X509Name(subjectDirName));
            certificateGenerator.SetNotBefore(startDate);
            certificateGenerator.SetNotAfter(endDate);
            certificateGenerator.SetPublicKey(encryptionKeys.Public);

            // selfsign certificate
            X509Certificate certificate = certificateGenerator.Generate(encryptionKeys.Private, random);

            var    store            = new Pkcs12Store();
            string friendlyName     = certificate.SubjectDN.ToString();
            var    certificateEntry = new X509CertificateEntry(certificate);

            store.SetCertificateEntry(friendlyName, certificateEntry);
            store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(encryptionKeys.Private), new[] { certificateEntry });

            var stream = new MemoryStream();

            store.Save(stream, "SuPerS3cr#2Pawd!".ToCharArray(), random);

            //Verify that the certificate is valid.
            return(new X509Certificate2(stream.ToArray(), "SuPerS3cr#2Pawd!", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable));
        }
Esempio n. 11
0
        public static void GenerateSignedCertificate(X509Certificate2 caCertificate, string subjectDirName, DateTime startDate, DateTime endDate, int signatureBits, int keyStrength, string password, string fileName)
        {
            string signatureAlgorithm;

            switch (signatureBits)
            {
            case 160:
                signatureAlgorithm = "SHA1withRSA";
                break;

            case 224:
                signatureAlgorithm = "SHA224withRSA";
                break;

            case 256:
                signatureAlgorithm = "SHA256withRSA";
                break;

            case 384:
                signatureAlgorithm = "SHA384withRSA";
                break;

            case 512:
                signatureAlgorithm = "SHA512withRSA";
                break;

            default:
                throw new ArgumentException("Invalid signature bit size.", "signatureBits");
            }

            // Generating Random Numbers
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom             random          = new SecureRandom(randomGenerator);

            // Generate public/private keys.
            AsymmetricCipherKeyPair encryptionKeys;

            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
            RsaKeyPairGenerator     keyPairGenerator        = new RsaKeyPairGenerator();

            keyPairGenerator.Init(keyGenerationParameters);
            encryptionKeys = keyPairGenerator.GenerateKeyPair();

            // The Certificate Generator
            X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

            certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random));
            certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
            certificateGenerator.SetIssuerDN(new X509Name(subjectDirName));
            certificateGenerator.SetSubjectDN(new X509Name(subjectDirName));
            certificateGenerator.SetNotBefore(startDate);
            certificateGenerator.SetNotAfter(endDate);
            certificateGenerator.SetPublicKey(encryptionKeys.Public);

            var parameters  = DotNetUtilities.GetRsaKeyPair(caCertificate.PrivateKey as RSA);
            var parameters2 = DotNetUtilities.GetRsaKeyPair((caCertificate.PrivateKey as RSA).ExportParameters(true));

            var cert  = caCertificate.PrivateKey as RSACryptoServiceProvider;
            var cert2 = DotNetUtilities.FromX509Certificate(caCertificate);

            // selfsign certificate
            X509Certificate certificate = certificateGenerator.Generate(parameters.Private, random);

            var    store            = new Pkcs12Store();
            string friendlyName     = certificate.SubjectDN.ToString();
            var    certificateEntry = new X509CertificateEntry(certificate);

            store.SetCertificateEntry(friendlyName, certificateEntry);
            store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(encryptionKeys.Private), new[] { certificateEntry });

            var stream = new MemoryStream();

            store.Save(stream, password.ToCharArray(), random);

            //Verify that the certificate is valid.
            var convertedCertificate = new X509Certificate2(stream.ToArray(), password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

            //Write the file.
            File.WriteAllBytes(fileName, stream.ToArray());
        }
Esempio n. 12
0
        /// <summary>
        /// Creates a cert with the connectionstring (token) and stores it in the given cert store.
        /// </summary>
        public static async Task WriteAsync(string name, string connectionString, string storeType, string storePath)
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new ArgumentException("Token not found in X509Store and no new token provided!");
            }

            SecureRandom            random = new SecureRandom();
            KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, 2048);
            RsaKeyPairGenerator     keyPairGenerator        = new RsaKeyPairGenerator();

            keyPairGenerator.Init(keyGenerationParameters);
            AsymmetricCipherKeyPair keys = keyPairGenerator.GenerateKeyPair();

            ArrayList nameOids = new ArrayList();

            nameOids.Add(X509Name.CN);
            ArrayList nameValues = new ArrayList();

            nameValues.Add(name);
            X509Name subjectDN = new X509Name(nameOids, nameValues);
            X509Name issuerDN  = subjectDN;

            X509V3CertificateGenerator cg = new X509V3CertificateGenerator();

            cg.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random));
            cg.SetIssuerDN(issuerDN);
            cg.SetSubjectDN(subjectDN);
            cg.SetNotBefore(DateTime.Now);
            cg.SetNotAfter(DateTime.Now.AddMonths(12));
            cg.SetPublicKey(keys.Public);
            cg.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DataEncipherment));

            // encrypt the token with the public key so only the owner of the assoc. private key can decrypt it and
            // "hide" it in the instruction code cert extension
            RSA              rsa       = RSA.Create();
            RSAParameters    rsaParams = new RSAParameters();
            RsaKeyParameters keyParams = (RsaKeyParameters)keys.Public;

            rsaParams.Modulus = new byte[keyParams.Modulus.ToByteArrayUnsigned().Length];
            keyParams.Modulus.ToByteArrayUnsigned().CopyTo(rsaParams.Modulus, 0);

            rsaParams.Exponent = new byte[keyParams.Exponent.ToByteArrayUnsigned().Length];
            keyParams.Exponent.ToByteArrayUnsigned().CopyTo(rsaParams.Exponent, 0);

            rsa.ImportParameters(rsaParams);
            if (rsa != null)
            {
                byte[] bytes = rsa.Encrypt(Encoding.ASCII.GetBytes(connectionString), RSAEncryptionPadding.OaepSHA1);
                if (bytes != null)
                {
                    cg.AddExtension(X509Extensions.InstructionCode, false, bytes);
                }
                else
                {
                    throw new CryptographicException("Can not encrypt IoTHub security token using generated public key!");
                }
            }

            // sign the cert with the private key
            ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keys.Private, random);

            Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

            // create a PKCS12 store for the cert and its private key
            X509Certificate2 certificate = null;

            using (MemoryStream pfxData = new MemoryStream())
            {
                Pkcs12StoreBuilder builder = new Pkcs12StoreBuilder();
                builder.SetUseDerEncoding(true);
                Pkcs12Store            pkcsStore = builder.Build();
                X509CertificateEntry[] chain     = new X509CertificateEntry[1];
                string passcode = Guid.NewGuid().ToString();
                chain[0] = new X509CertificateEntry(x509);
                pkcsStore.SetKeyEntry(name, new AsymmetricKeyEntry(keys.Private), chain);
                pkcsStore.Save(pfxData, passcode.ToCharArray(), random);

                // create X509Certificate2 object from PKCS12 file
                certificate = CertificateFactory.CreateCertificateFromPKCS12(pfxData.ToArray(), passcode);

                // handle each store type differently
                switch (storeType)
                {
                case CertificateStoreType.Directory:
                {
                    // Add to DirectoryStore
                    using (DirectoryCertificateStore store = new DirectoryCertificateStore())
                    {
                        store.Open(storePath);
                        X509CertificateCollection certificates = await store.Enumerate().ConfigureAwait(false);

                        // remove any existing cert with our name from the store
                        foreach (X509Certificate2 cert in certificates)
                        {
                            if (cert.SubjectName.Decode(X500DistinguishedNameFlags.None | X500DistinguishedNameFlags.DoNotUseQuotes).Equals("CN=" + name, StringComparison.OrdinalIgnoreCase))
                            {
                                await store.Delete(cert.Thumbprint).ConfigureAwait(false);
                            }
                        }

                        // add new one
                        await store.Add(certificate).ConfigureAwait(false);
                    }
                    break;
                }

                case CertificateStoreType.X509Store:
                {
                    // Add to X509Store
                    using (X509Store store = new X509Store(storePath, StoreLocation.CurrentUser))
                    {
                        store.Open(OpenFlags.ReadWrite);

                        // remove any existing cert with our name from the store
                        foreach (X509Certificate2 cert in store.Certificates)
                        {
                            if (cert.SubjectName.Decode(X500DistinguishedNameFlags.None | X500DistinguishedNameFlags.DoNotUseQuotes).Equals("CN=" + name, StringComparison.OrdinalIgnoreCase))
                            {
                                store.Remove(cert);
                            }
                        }

                        // add new cert to store
                        try
                        {
                            store.Add(certificate);
                        }
                        catch (Exception e)
                        {
                            throw new Exception($"Not able to add cert to the requested store type '{storeType}' (exception message: '{e.Message}'.");
                        }
                    }
                    break;
                }

                default:
                {
                    throw new Exception($"The requested store type '{storeType}' is not supported. Please change.");
                }
                }
                return;
            }
        }
Esempio n. 13
0
        ///// <summary>
        ///// Create a new certificate
        ///// </summary>
        ///// <param name="issuer">Issuer certificate, if null then self-sign</param>
        ///// <param name="subjectName">Subject name</param>
        ///// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param>
        ///// <param name="keySize">Size of RSA key</param>
        ///// <param name="notBefore">Start date of certificate</param>
        ///// <param name="notAfter">End date of certificate</param>
        ///// <param name="extensions">Array of extensions, if null then no extensions</param>
        ///// <param name="hashAlgorithm">Specify the signature hash algorithm</param>
        ///// <returns>The created X509 certificate</returns>
        public static SystemX509.X509Certificate2 CreateCert(SystemX509.X509Certificate2 issuer, SystemX509.X500DistinguishedName subjectName,
                                                             byte[] serialNumber, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore,
                                                             DateTime notAfter, SystemX509.X509ExtensionCollection extensions)
        {
            SecureRandom random = new SecureRandom();
            X509V3CertificateGenerator builder      = new X509V3CertificateGenerator();
            AsymmetricCipherKeyPair    bcSubjectKey = CreateRSAKey(keySize, random);
            AsymmetricCipherKeyPair    bcSignKey    = issuer == null ? bcSubjectKey : issuer.GetBCPrivateKey();

            if (bcSignKey == null)
            {
                throw new ArgumentException("issuer");
            }

            X509Name issuerNameObj = issuer == null?X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData))
                                         : X509Name.GetInstance(Asn1Object.FromByteArray(issuer.SubjectName.RawData));

            X509Name subjectNameObj = X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData));

            BigInteger subjectSerial = new BigInteger(1, serialNumber != null ? serialNumber : Guid.NewGuid().ToByteArray());
            BigInteger issuerSerial  = issuer == null ? subjectSerial : new BigInteger(1, issuer.GetSerialNumber());

            builder.SetIssuerDN(issuerNameObj);
            builder.SetSubjectDN(subjectNameObj);
            builder.SetSerialNumber(subjectSerial);
            builder.SetNotBefore(notBefore.ToUniversalTime());
            builder.SetNotAfter(notAfter.ToUniversalTime());
            builder.SetPublicKey(bcSubjectKey.Public);

            SubjectPublicKeyInfo   info         = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSignKey.Public);
            AuthorityKeyIdentifier authKeyId    = new AuthorityKeyIdentifier(info, new GeneralNames(new GeneralName(issuerNameObj)), issuerSerial);
            SubjectKeyIdentifier   subjectKeyid = new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSubjectKey.Public));

            builder.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authKeyId);
            builder.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, true, subjectKeyid);

            if (extensions != null)
            {
                foreach (SystemX509.X509Extension ext in extensions)
                {
                    if (!ext.Oid.Value.Equals(X509Extensions.AuthorityKeyIdentifier.Id) &&
                        !ext.Oid.Value.Equals(X509Extensions.SubjectKeyIdentifier.Id) &&
                        !ext.Oid.Value.Equals(szOID_AUTHORITY_KEY_IDENTIFIER2))
                    {
                        Asn1InputStream istm = new Asn1InputStream(ext.RawData);
                        Asn1Object      obj  = istm.ReadObject();
                        builder.AddExtension(ext.Oid.Value, ext.Critical, obj);
                    }
                }
            }

            X509Certificate cert = builder.Generate(CreateSignatureFactory(hashAlgorithm, bcSignKey, random));

            Pkcs12StoreBuilder   pkcs  = new Pkcs12StoreBuilder();
            Pkcs12Store          store = pkcs.Build();
            X509CertificateEntry entry = new X509CertificateEntry(cert);

            store.SetCertificateEntry("main", entry);

            AsymmetricKeyEntry key_entry = new AsymmetricKeyEntry(bcSubjectKey.Private);

            store.SetKeyEntry("main", key_entry, new[] { entry });
            MemoryStream stm = new MemoryStream();

            store.Save(stm, new char[0], new SecureRandom());
            return(new SystemX509.X509Certificate2(stm.ToArray(), String.Empty, SystemX509.X509KeyStorageFlags.Exportable));
        }
        public override async Task PairAsync(string ipAddress, TextBox outputTextBox)
        {
            // Create SHA256 hash digest. This is not supported by server version < 7
            // (need to use SHA1 for those cases) but that doesn't really matter right now.
            IDigest hashAlgorithm  = new Sha256Digest();
            int     hashDigestSize = hashAlgorithm.GetDigestSize();

            // Create and salt pin
            byte[] salt = this.GenerateRandomBytes(16);
            string pin  = GenerateRandomPin();

            byte[] saltAndPin = SaltPin(salt, pin);

            // Asymmetric key pair
            RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();

            keyPairGenerator.Init(new KeyGenerationParameters(this.SecureRandom, 2048));
            AsymmetricCipherKeyPair keyPair = keyPairGenerator.GenerateKeyPair();

            // Certificate issuer and name
            X509Name name = new X509Name("CN=NVIDIA GameStream Client");

            // Certificate serial number
            byte[]     serialBytes = this.GenerateRandomBytes(8);
            BigInteger serial      = new BigInteger(serialBytes).Abs();

            // Expires in 20 years
            DateTime now        = DateTime.UtcNow;
            DateTime expiration = now.AddYears(20);

            X509V3CertificateGenerator generator = new X509V3CertificateGenerator();

            generator.SetSubjectDN(name);
            generator.SetIssuerDN(name);
            generator.SetSerialNumber(serial);
            generator.SetNotBefore(now);
            generator.SetNotAfter(expiration);
            generator.SetPublicKey(keyPair.Public);

            BouncyCastleX509Certificate certificate =
                generator.Generate(
                    new Asn1SignatureFactory("SHA1WithRSA", keyPair.Private));

            // Create PKCS12 certificate bytes.
            Pkcs12Store          store            = new Pkcs12Store();
            X509CertificateEntry certificateEntry = new X509CertificateEntry(certificate);
            string friendlyName = "Moonlight Xbox";
            string password     = "******";

            store.SetCertificateEntry(friendlyName, certificateEntry);
            store.SetKeyEntry(
                friendlyName,
                new AsymmetricKeyEntry(keyPair.Private),
                new X509CertificateEntry[] { certificateEntry });
            byte[] pfxDataBytes;
            using (MemoryStream memoryStream = new MemoryStream(512))
            {
                store.Save(memoryStream, password.ToCharArray(), this.SecureRandom);
                pfxDataBytes = memoryStream.ToArray();
            }

            await CertificateEnrollmentManager.ImportPfxDataAsync(
                CryptographicBuffer.EncodeToBase64String(pfxDataBytes.AsBuffer()),
                password,
                ExportOption.NotExportable,
                KeyProtectionLevel.NoConsent,
                InstallOptions.DeleteExpired,
                friendlyName);

            // Create the system certificate.
            X509Certificate2 systemCertificate =
                new X509Certificate2(
                    pfxDataBytes,
                    password,
                    X509KeyStorageFlags.PersistKeySet);

            string keyString;

            using (StringWriter keyWriter = new StringWriter())
            {
                PemWriter pemWriter = new PemWriter(keyWriter);
                pemWriter.WriteObject(keyPair);
                keyString = keyWriter.ToString();

                // Line endings must be UNIX style for GFE to accept the certificate.
                keyString = keyString.Replace(Environment.NewLine, "\n");
            }

            string certString;

            using (StringWriter certWriter = new StringWriter())
            {
                PemWriter pemWriter = new PemWriter(certWriter);
                pemWriter.WriteObject(certificate);
                certString = certWriter.ToString();

                // Line endings must be UNIX style for GFE to accept the certificate.
                certString = certString.Replace(Environment.NewLine, "\n");
            }

            byte[] pemCertBytes = Encoding.UTF8.GetBytes(certString);
            byte[] uniqueId     = GenerateRandomBytes(8);

            // Create the HTTP client.
            HttpClientHandler handler = new HttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true;
            handler.ClientCertificates.Add(systemCertificate);

            HttpClient httpClient = new HttpClient(handler);

            httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,*");
            httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0");

            // Unpair before doing anything else in this test app.
            string uriString =
                string.Format(
                    "http://{0}:47989/unpair?uniqueid={1}&uuid={2}",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"));

            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Unpair status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                }
            }

            await Task.Delay(2000);

            outputTextBox.Text = $"Enter pin: {pin}";

            // Get server certificate.
            // TODO: Call should have no timeout because it requires the user to enter a pin.
            PairResponse pairResponse = null;

            uriString =
                string.Format(
                    "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&phrase=getservercert&salt={3}&clientcert={4}",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"),
                    BytesToHex(salt),
                    BytesToHex(pemCertBytes));
            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Get server cert status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                    using (StringReader reader = new StringReader(responseContent))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(PairResponse));
                        pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse;
                    }
                }
            }

            if (pairResponse == null || pairResponse.Paired != 1)
            {
                outputTextBox.Text += "Pairing failed.\n";
                return;
            }

            if (string.IsNullOrEmpty(pairResponse.PlainCert))
            {
                outputTextBox.Text += "Pairing already in progress.\n";
                return;
            }

            // Parse server certificate
            byte[] serverCertBytes = HexToBytes(pairResponse.PlainCert);
            BouncyCastleX509Certificate serverCertificate = new X509CertificateParser().ReadCertificate(serverCertBytes);

            // Hash the salt and pin and use it to generate an AES key.
            byte[]            hashedSaltAndPin = HashData(hashAlgorithm, saltAndPin);
            ICipherParameters aesKey           = GenerateCipherKey(hashedSaltAndPin);

            // Generate a random challenge and encrypt it using AES.
            byte[] challenge          = GenerateRandomBytes(16);
            byte[] encryptedChallenge = DoAesCipher(true, aesKey, challenge);

            await Task.Delay(2000);

            // Send the encrypted challenge to the server.
            // TODO: Call should have a timeout.
            uriString =
                string.Format(
                    "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&clientchallenge={3}",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"),
                    BytesToHex(encryptedChallenge));
            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Send challenge status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                    using (StringReader reader = new StringReader(responseContent))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(PairResponse));
                        pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse;
                    }
                }
            }

            if (pairResponse == null || pairResponse.Paired != 1)
            {
                outputTextBox.Text += "Pairing failed.\n";
                return;
            }

            // Decode the server's response and subsequent challenge.
            byte[] encryptedServerChallengeResponse = HexToBytes(pairResponse.ChallengeResponse);
            byte[] decryptedServerChallengeResponse = DoAesCipher(false, aesKey, encryptedServerChallengeResponse);

            byte[] serverResponse  = new byte[hashDigestSize];
            byte[] serverChallenge = new byte[16];
            Array.Copy(decryptedServerChallengeResponse, serverResponse, hashDigestSize);
            Array.Copy(decryptedServerChallengeResponse, hashDigestSize, serverChallenge, 0, 16);

            // Using another 16 byte secret, compute a challenge response hash using the secret,
            // our certificate signature, and the challenge.
            byte[] clientSecret          = GenerateRandomBytes(16);
            byte[] challengeResponseHash =
                HashData(
                    hashAlgorithm,
                    ConcatenateByteArrays(serverChallenge, certificate.GetSignature(), clientSecret));
            byte[] encryptedChallengeResponse = DoAesCipher(true, aesKey, challengeResponseHash);

            await Task.Delay(2000);

            // Send the challenge response to the server.
            // TODO: Call should have a timeout.
            uriString =
                string.Format(
                    "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&serverchallengeresp={3}",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"),
                    BytesToHex(encryptedChallengeResponse));
            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Send challenge response status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                    using (StringReader reader = new StringReader(responseContent))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(PairResponse));
                        pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse;
                    }
                }
            }

            if (pairResponse == null || pairResponse.Paired != 1)
            {
                outputTextBox.Text += "Pairing failed.\n";
                // TODO: Unpair here by calling http://<blah>/unpair?uniqueid={1}&uuid={2}.
                return;
            }

            // Get the server's signed secret.
            byte[] serverSecretResponse = HexToBytes(pairResponse.PairingSecret);
            byte[] serverSecret         = new byte[16];
            byte[] serverSignature      = new byte[256];
            Array.Copy(serverSecretResponse, serverSecret, serverSecret.Length);
            Array.Copy(serverSecretResponse, serverSecret.Length, serverSignature, 0, serverSignature.Length);

            if (!VerifySignature(serverSecret, serverSignature, serverCertificate.GetPublicKey()))
            {
                outputTextBox.Text += "Pairing failed.\n";
                // TODO: Unpair as above.
                return;
            }

            // Ensure the server challenge matched what we expected (the PIN was correct).
            byte[] serverChallengeResponseHash =
                HashData(
                    hashAlgorithm,
                    ConcatenateByteArrays(
                        challenge,
                        serverCertificate.GetSignature(),
                        serverSecret));
            if (!serverChallengeResponseHash.SequenceEqual(serverResponse))
            {
                outputTextBox.Text += "Pairing failed due to wrong pin.\n";
                // TODO: Unpair as above.
                return;
            }

            await Task.Delay(2000);

            // Send the server our signed secret
            // TODO: Call should have a timeout.
            byte[] signedSecret        = SignData(clientSecret, keyPair.Private);
            byte[] clientPairingSecret =
                ConcatenateByteArrays(
                    clientSecret,
                    signedSecret);
            uriString =
                string.Format(
                    "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&clientpairingsecret={3}",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"),
                    BytesToHex(clientPairingSecret));
            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Send client pairing secret status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                    using (StringReader reader = new StringReader(responseContent))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(PairResponse));
                        pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse;
                    }
                }
            }

            if (pairResponse == null || pairResponse.Paired != 1)
            {
                outputTextBox.Text += "Pairing failed.\n";
                // TODO: Unpair as above.
                return;
            }

            await Task.Delay(2000);

            // Do the initial challenge (seems neccessary for us to show as paired).
            // TODO: Call should have a timeout.
            uriString =
                string.Format(
                    "https://{0}:47984/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&phrase=pairchallenge",
                    ipAddress,
                    BytesToHex(uniqueId),
                    Guid.NewGuid().ToString("N"));
            using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString)))
            {
                using (HttpResponseMessage response = await httpClient.SendAsync(request))
                {
                    outputTextBox.Text = $"Send pair challenge status code: {response.StatusCode}\n";
                    string responseContent = await response.Content.ReadAsStringAsync();

                    outputTextBox.Text += responseContent + "\n";
                    using (StringReader reader = new StringReader(responseContent))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(PairResponse));
                        pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse;
                    }
                }
            }

            if (pairResponse == null || pairResponse.Paired != 1)
            {
                outputTextBox.Text += "Pairing failed.\n";
                // TODO: Unpair as above.
                return;
            }

            await Task.Delay(2000);

            outputTextBox.Text = "Pairing succeeded!\n";
        }