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)); }
// [DataRow(PkiAsymmetricAlgorithm.Ecdsa, 256, PkiEncodingFormat.Pem)] public void ExportImportCsr(PkiAsymmetricAlgorithm algor, int bits, PkiEncodingFormat format) { var hashAlgor = PkiHashAlgorithm.Sha256; var sn = "CN=foo.example.com"; var sans = new[] { "foo-alt1.example.com", "foo-alt2.example.com", }; var keys = PkiKeyTests.GenerateKeyPair(algor, bits); var csr = new PkiCertificateSigningRequest(sn, keys, hashAlgor); csr.CertificateExtensions.Add( PkiCertificateExtension.CreateDnsSubjectAlternativeNames(sans)); var saveOut = Path.Combine(_testTemp, $"csrexport-{algor}-{bits}-{hashAlgor}-sans.{format}"); var encoding = csr.ExportSigningRequest(format); File.WriteAllBytes(saveOut, encoding); encoding = File.ReadAllBytes(saveOut); PkiCertificateSigningRequest csr2 = new PkiCertificateSigningRequest(format, encoding, hashAlgor); using (var ms = new MemoryStream()) { csr2.Save(ms); File.WriteAllBytes(saveOut + 2, ms.ToArray()); } // File.WriteAllBytes(saveOut + "1a.pem", csr.ExportSigningRequest(PkiEncodingFormat.Pem)); // File.WriteAllBytes(saveOut + "1b.pem", csr.ExportSigningRequest(PkiEncodingFormat.Pem)); // File.WriteAllBytes(saveOut + "2a.pem", csr2.ExportSigningRequest(PkiEncodingFormat.Pem)); // File.WriteAllBytes(saveOut + "2b.pem", csr2.ExportSigningRequest(PkiEncodingFormat.Pem)); Assert.AreEqual(csr.SubjectName, csr2.SubjectName); Assert.AreEqual(csr.HashAlgorithm, csr2.HashAlgorithm); CollectionAssert.AreEqual( csr.PublicKey.Export(PkiEncodingFormat.Der), csr2.PublicKey.Export(PkiEncodingFormat.Der)); CollectionAssert.AreEqual( csr.CertificateExtensions, csr2.CertificateExtensions, CertExtComparerInstance); Assert.AreEqual(csr.PublicKey.IsPrivate, csr2.PublicKey.IsPrivate); Assert.AreEqual(csr.PublicKey.Algorithm, csr2.PublicKey.Algorithm); CollectionAssert.AreEqual( csr.PublicKey.Export(PkiEncodingFormat.Der), csr2.PublicKey.Export(PkiEncodingFormat.Der)); }
public byte[] Export(PkiEncodingFormat format) { switch (format) { case PkiEncodingFormat.Pem: using (var sw = new StringWriter()) { var pemWriter = new PemWriter(sw); pemWriter.WriteObject(NativeCertificate); return(Encoding.UTF8.GetBytes(sw.GetStringBuilder().ToString())); } case PkiEncodingFormat.Der: return(NativeCertificate.GetEncoded()); default: throw new NotSupportedException(); } }
/// <summary> /// Exports the key into a supported key format. /// </summary> public byte[] Export(PkiEncodingFormat format, char[] password = null) { switch (format) { case PkiEncodingFormat.Pem: using (var sw = new StringWriter()) { object pemObject = NativeKey; if (IsPrivate && password != null) { var pkcs8Gen = new Pkcs8Generator(NativeKey, Pkcs8Generator.PbeSha1_3DES); pkcs8Gen.Password = password; pemObject = pkcs8Gen.Generate(); } var pemWriter = new PemWriter(sw); pemWriter.WriteObject(pemObject); return(Encoding.UTF8.GetBytes(sw.GetStringBuilder().ToString())); } case PkiEncodingFormat.Der: if (IsPrivate) { var keyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(NativeKey); return(keyInfo.GetDerEncoded()); } else { var keyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(NativeKey); return(keyInfo.GetDerEncoded()); } default: throw new NotSupportedException(); } }
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; } } } } }
/// <summary> /// Creates an ASN.1 DER-encoded PKCS#10 CertificationRequest object representing /// the current state of this CertificateRequest object. /// </summary> /// <returns>An ASN.1 DER-encoded certificate signing request.</returns> public byte[] ExportSigningRequest(PkiEncodingFormat format) { if (!HasPrivateKey) { throw new InvalidOperationException("cannot export CSR without a private key"); } // Based on: // https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/pkcs/test/PKCS10Test.cs // https://stackoverflow.com/questions/46182659/how-to-delay-sign-the-certificate-request-using-bouncy-castle-with-ecdsa-signatu // http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation: // #X.509PublicKeyCertificateandCertificationRequestGeneration-EllipticCurve(ECDSA) // #X.509PublicKeyCertificateandCertificationRequestGeneration-RSA // #X.509PublicKeyCertificateandCertificationRequestGeneration-CreatingCertificationRequests // https://stackoverflow.com/a/37563051/5428506 var x509name = new X509Name(SubjectName); var pubKey = _keyPair.PublicKey.NativeKey; var prvKey = _keyPair.PrivateKey.NativeKey; // Asn1Set attrSet = null; // if (CertificateExtensions.Count > 0) // { // var certExts = CertificateExtensions.ToDictionary( // ext => ext.Identifier, ext => ext.Value); // var csrAttrs = new[] // { // new Org.BouncyCastle.Asn1.Cms.Attribute( // PkcsObjectIdentifiers.Pkcs9AtExtensionRequest, // new DerSet(new X509Extensions(certExts))), // }; // attrSet = new DerSet(csrAttrs); // } // 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())); var sigFactory = ComputeSignatureAlgorithm(prvKey); var pkcs10 = new Pkcs10CertificationRequest(sigFactory, x509name, pubKey, new DerSet(attr), prvKey); switch (format) { case PkiEncodingFormat.Pem: using (var sw = new StringWriter()) { var pemWriter = new PemWriter(sw); pemWriter.WriteObject(pkcs10); return(Encoding.UTF8.GetBytes(sw.GetStringBuilder().ToString())); } case PkiEncodingFormat.Der: return(pkcs10.GetDerEncoded()); default: throw new NotSupportedException(); } }