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); } }
/// <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; }
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)); }
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); } }
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; } } } } }