Example #1
0
        public void CreateAndExportRsaCsr(int bits, PkiHashAlgorithm hashAlgor)
        {
            var sn   = "CN=foo.example.com";
            var keys = PkiKeyPair.GenerateRsaKeyPair(bits);
            var csr  = new PkiCertificateSigningRequest(sn, keys, hashAlgor);

            var pemOut = Path.Combine(_testTemp,
                                      $"csr-rsa-{bits}-{hashAlgor}.pem");
            var derOut = Path.Combine(_testTemp,
                                      $"csr-rsa-{bits}-{hashAlgor}.der");

            Assert.AreEqual(sn, csr.SubjectName);
            Assert.AreSame(keys.PublicKey, keys.PublicKey);
            Assert.AreEqual(hashAlgor, csr.HashAlgorithm);

            File.WriteAllBytes(pemOut, csr.ExportSigningRequest(PkiEncodingFormat.Pem));
            File.WriteAllBytes(derOut, csr.ExportSigningRequest(PkiEncodingFormat.Der));

            using (var proc = OpenSsl.Start($"req -text -noout -verify -in {pemOut}"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }

            using (var proc = OpenSsl.Start($"req -text -noout -verify -inform DER -in {derOut}"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }
        }
Example #2
0
 /// <summary>
 /// Creates a new instance of a PKI Certificate Signing Request.
 /// </summary>
 /// <param name="subjectName">The Subject Name of the Certificate Request in X509
 ///         directory format, e.g. <c>CN=app.example.com</c>.</param>
 /// <param name="keyPair">A public/private key pair.</param>
 /// <param name="hashAlgorithm">The hash algorithm to be used.</param>
 public PkiCertificateSigningRequest(string subjectName, PkiKeyPair keyPair,
                                     PkiHashAlgorithm hashAlgorithm)
 {
     SubjectName   = subjectName;
     _keyPair      = keyPair;
     PublicKey     = _keyPair.PublicKey;
     HashAlgorithm = hashAlgorithm;
 }
Example #3
0
        public PkiCertificate Sign(PkiEncodingFormat format, byte[] encodedCsr,
                                   PkiHashAlgorithm signingHashAlgorithm,
                                   DateTimeOffset?notBefore = null,
                                   DateTimeOffset?notAfter  = null)
        {
            var csr = new PkiCertificateSigningRequest(format, encodedCsr, signingHashAlgorithm);

            return(Sign(csr, notBefore, notAfter));
        }
Example #4
0
        public void CreateAndExportEcdsaSansCsr(int bits, PkiHashAlgorithm hashAlgor)
        {
            var sn   = "CN=foo.example.com";
            var sans = new[] {
                "foo-alt1.example.com",
                "foo-alt2.example.com",
            };
            var keys = PkiKeyPair.GenerateEcdsaKeyPair(bits);
            var csr  = new PkiCertificateSigningRequest(sn, keys, hashAlgor);

            csr.CertificateExtensions.Add(
                PkiCertificateExtension.CreateDnsSubjectAlternativeNames(sans));

            var pemOut = Path.Combine(_testTemp,
                                      $"csr-ecdsa-{bits}-{hashAlgor}-sans.pem");
            var derOut = Path.Combine(_testTemp,
                                      $"csr-ecdsa-{bits}-{hashAlgor}-sans.der");

            Assert.AreEqual(sn, csr.SubjectName);
            Assert.AreSame(keys.PublicKey, keys.PublicKey);
            Assert.AreEqual(hashAlgor, csr.HashAlgorithm);
            Assert.AreEqual(1, csr.CertificateExtensions.Count);

            File.WriteAllBytes(pemOut, csr.ExportSigningRequest(PkiEncodingFormat.Pem));
            File.WriteAllBytes(derOut, csr.ExportSigningRequest(PkiEncodingFormat.Der));

            using (var proc = OpenSsl.Start($"req -text -noout -verify -in {pemOut}"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }

            using (var proc = OpenSsl.Start($"req -text -noout -verify -inform DER -in {derOut}"))
            {
                proc.WaitForExit();
                Assert.AreEqual(0, proc.ExitCode);
            }
        }
Example #5
0
        public PkiCertificateSigningRequest(PkiEncodingFormat format, byte[] encoded,
                                            PkiHashAlgorithm hashAlgorithm)
        {
            Pkcs10CertificationRequest pkcs10;

            switch (format)
            {
            case PkiEncodingFormat.Pem:
                var encodedString = Encoding.UTF8.GetString(encoded);
                using (var sr = new StringReader(encodedString))
                {
                    var pemReader = new PemReader(sr);
                    pkcs10 = pemReader.ReadObject() as Pkcs10CertificationRequest;
                    if (pkcs10 == null)
                    {
                        throw new Exception("invalid PEM object is not PKCS#10 archive");
                    }
                }
                break;

            case PkiEncodingFormat.Der:
                pkcs10 = new Pkcs10CertificationRequest(encoded);
                break;

            default:
                throw new NotSupportedException();
            }

            var info            = pkcs10.GetCertificationRequestInfo();
            var nativePublicKey = pkcs10.GetPublicKey();
            var rsaKey          = nativePublicKey as RsaKeyParameters;
            var ecdsaKey        = nativePublicKey as ECPublicKeyParameters;

            if (rsaKey != null)
            {
                PublicKey = new PkiKey(nativePublicKey, PkiAsymmetricAlgorithm.Rsa);
            }
            else if (ecdsaKey != null)
            {
                PublicKey = new PkiKey(nativePublicKey, PkiAsymmetricAlgorithm.Ecdsa);
            }
            else
            {
                throw new NotSupportedException("unsupported asymmetric algorithm key");
            }
            SubjectName   = info.Subject.ToString();
            HashAlgorithm = hashAlgorithm;


            // // // Based on:
            // // //    http://forum.rebex.net/4284/pkcs10-certificate-request-example-provided-castle-working

            // // var extGen = new X509ExtensionsGenerator();
            // // foreach (var ext in CertificateExtensions)
            // // {
            // //     extGen.AddExtension(ext.Identifier, ext.IsCritical, ext.Value);
            // // }
            // // var attr = new AttributeX509(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
            // //         new DerSet(extGen.Generate()));


            // Based on:
            //    http://unitstep.net/blog/2008/10/27/extracting-x509-extensions-from-a-csr-using-the-bouncy-castle-apis/
            //    https://stackoverflow.com/q/24448909/5428506
            foreach (var attr in info.Attributes.ToArray())
            {
                if (attr is DerSequence derSeq && derSeq.Count == 2)
                {
                    var attrX509 = AttributeX509.GetInstance(attr);
                    if (object.Equals(attrX509.AttrType, PkcsObjectIdentifiers.Pkcs9AtExtensionRequest))
                    {
                        // The `Extension Request` attribute is present.
                        // The X509Extensions are contained as a value of the ASN.1 Set.
                        // Assume that it is the first value of the set.
                        if (attrX509.AttrValues.Count >= 1)
                        {
                            var csrExts = X509Extensions.GetInstance(attrX509.AttrValues[0]);
                            foreach (var extOid in csrExts.GetExtensionOids())
                            {
                                if (object.Equals(extOid, X509Extensions.SubjectAlternativeName))
                                {
                                    var ext    = csrExts.GetExtension(extOid);
                                    var extVal = ext.Value;
                                    var der    = extVal.GetDerEncoded();
                                    // The ext value, which is an ASN.1 Octet String, **MIGHT** be tagged with
                                    // a leading indicator that it's an Octet String and its length, so we want
                                    // to remove it if that's the case to extract the GeneralNames collection
                                    if (der.Length > 2 && der[0] == 4 && der[1] == der.Length - 2)
                                    {
                                        der = der.Skip(2).ToArray();
                                    }
                                    var asn1obj = Asn1Object.FromByteArray(der);
                                    var gnames  = GeneralNames.GetInstance(asn1obj);
                                    CertificateExtensions.Add(new PkiCertificateExtension
                                    {
                                        Identifier = extOid,
                                        IsCritical = ext.IsCritical,
                                        Value      = gnames,
                                    });
                                }
                            }

                            // No need to search any more.
                            break;
                        }
                    }
                }
            }
        }