Exemple #1
0
        /// <summary>
        /// Creates a certificate using the established subject, key, and optional
        /// extensions using the specified certificate as the issuer.
        /// </summary>
        /// <param name="issuerCertificate">Certificate instance representing the issuing
        ///         Certificate Authority (CA).</param>
        /// <param name="issuerPrivatekey">Key representing the private key of the issuing
        ///         certificate authority.
        /// <param name="notBefore">The oldest date and time when this certificate is considered
        ///         valid. Typically UtcNow, plus or minus a few seconds.</param>
        /// <param name="notAfter">The date and time when this certificate is no longer considered
        ///         valid.</param>
        /// <param name="serialNumber">The serial number to use for the new certificate.
        ///         This value should be unique per issuer. The value is interpreted as
        ///         an unsigned integer of arbitrary size in big-endian byte ordering.
        ///         RFC 3280 recommends confining it to 20 bytes or less.</param>
        /// <returns>A Certificate with the specified values. The returned object
        ///         won't assert HasPrivateKey.</returns>
        public PkiCertificate Create(PkiCertificate issuerCertificate, PkiKey issuerPrivateKey,
                                     DateTimeOffset notBefore, DateTimeOffset notAfter, byte[] serialNumber)
        {
            var isur = new X509Name(issuerCertificate.SubjectName);
            var name = new X509Name(SubjectName);

            return(Create(isur, issuerPrivateKey, name, notBefore, notAfter, serialNumber));
        }
Exemple #2
0
        internal static bool Verify(string algor, PkiKey pub, byte[] input, byte[] sig)
        {
            // Based on:
            //    http://mytenpennies.wikidot.com/blog:using-bouncy-castle

            var signer = SignerUtilities.GetSigner(algor);

            signer.Init(false, pub.NativeKey);
            signer.BlockUpdate(input, 0, input.Length);
            return(signer.VerifySignature(sig));
        }
Exemple #3
0
        internal static byte[] Sign(string algor, PkiKey prv, byte[] input, int transcodeLength = 0)
        {
            // Based on:
            //    http://mytenpennies.wikidot.com/blog:using-bouncy-castle

            var signer = SignerUtilities.GetSigner(algor);

            signer.Init(true, prv.NativeKey);
            signer.BlockUpdate(input, 0, input.Length);
            var sig = signer.GenerateSignature();

            if (transcodeLength != 0)
            {
                sig = TranscodeSignatureToConcat(sig, transcodeLength);
            }

            return(sig);
        }
Exemple #4
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;
                        }
                    }
                }
            }
        }
Exemple #5
0
        internal PkiCertificate Create(X509Name issuerName, PkiKey issuerPrivateKey,
                                       X509Name subjectName, DateTimeOffset notBefore, DateTimeOffset notAfter,
                                       byte[] serialNumber, X509KeyUsage keyUsage = null, KeyPurposeID[] extKeyUsage = null)
        {
            // Based on:
            //    https://stackoverflow.com/a/39456955/5428506
            //    https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/test/CertTest.cs

            var pubKey = _keyPair?.PublicKey.NativeKey ?? PublicKey.NativeKey;

            var sigFactory = ComputeSignatureAlgorithm(issuerPrivateKey.NativeKey);
            var certGen    = new X509V3CertificateGenerator();

            certGen.SetSerialNumber(new BigInteger(serialNumber));
            certGen.SetIssuerDN(issuerName);
            certGen.SetSubjectDN(subjectName);
            certGen.SetNotBefore(notBefore.UtcDateTime);
            certGen.SetNotAfter(notAfter.UtcDateTime);
            certGen.SetPublicKey(pubKey);

            if (keyUsage == null)
            {
                keyUsage = new X509KeyUsage(X509KeyUsage.KeyEncipherment |
                                            X509KeyUsage.DigitalSignature);
            }
            if (extKeyUsage == null)
            {
                extKeyUsage = new[] {
                    KeyPurposeID.IdKPClientAuth,
                    KeyPurposeID.IdKPServerAuth
                }
            }
            ;

            certGen.AddExtension("2.5.29.15", true, keyUsage);
            certGen.AddExtension("2.5.29.37", true, new DerSequence(extKeyUsage));

            // Based on:
            //    https://boredwookie.net/blog/bouncy-castle-add-a-subject-alternative-name-when-creating-a-cer

            foreach (var ext in CertificateExtensions)
            {
                // certGen.AddExtension(ext.Identifier, ext.Value.IsCritical, ext.Value.Value);
                certGen.AddExtension(ext.Identifier, ext.IsCritical, ext.Value);
            }

            var bcCert = certGen.Generate(sigFactory);

            return(new PkiCertificate
            {
                NativeCertificate = bcCert,
            });

            // Compare to LE-issued Certs:
            //    Enhanced Key Usage:
            //        Server Authentication (1.3.6.1.5.5.7.3.1)
            //        Client Authentication (1.3.6.1.5.5.7.3.2)
            //    Subject Key Identifier:
            //        e05bf2ba81d8d3845ff45b5638551e64ca19133d
            //    Authority Key Identifier:
            //        KeyID=a84a6a63047dddbae6d139b7a64565eff3a8eca1
            //    Authority Information Access:
            //        [1]Authority Info Access
            //            Access Method=On-line Certificate Status Protocol (1.3.6.1.5.5.7.48.1)
            //            Alternative Name:
            //                URL=http://ocsp.int-x3.letsencrypt.org
            //        [2]Authority Info Access
            //            Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
            //            Alternative Name:
            //                URL=http://cert.int-x3.letsencrypt.org/
            //    Certificate Policies:
            //        ...
            //    SCT List:
            //        ...
            //    Key Usage:
            //        Digital Signature, Key Encipherment (a0)
            //    Basic Constraints:
            //        Subject Type=End Entity
            //        Path Length Constraint=None

            // CA:
            //    Key Usage:
            //        Digital Signature, Certificate Signing, Off-line CRL Signing, CRL Signing (86)
        }
Exemple #6
0
        public byte[] Export(PkiArchiveFormat format, PkiKey privateKey = null,
                             IEnumerable <PkiCertificate> chain         = null,
                             char[] password = null)
        {
            // Based on:
            //    https://stackoverflow.com/a/44798441/5428506

            switch (format)
            {
            case PkiArchiveFormat.Pem:
                using (var buff = new MemoryStream())
                {
                    byte[] bytes = privateKey?.Export(PkiEncodingFormat.Pem, password);
                    if (bytes != null)
                    {
                        buff.Write(bytes, 0, bytes.Length);
                    }
                    bytes = Export(PkiEncodingFormat.Pem);
                    buff.Write(bytes, 0, bytes.Length);
                    if (chain != null)
                    {
                        foreach (var c in chain)
                        {
                            bytes = c.Export(PkiEncodingFormat.Pem);
                            buff.Write(bytes, 0, bytes.Length);
                        }
                    }
                    return(buff.ToArray());
                }

            case PkiArchiveFormat.Pkcs12:
                var alias = AliasOf(this);
                var store = new Pkcs12StoreBuilder().Build();
                if (privateKey != null)
                {
                    store.SetKeyEntry(alias, new AsymmetricKeyEntry(privateKey.NativeKey),
                                      new[] { new X509CertificateEntry(NativeCertificate) });
                }
                else
                {
                    store.SetCertificateEntry(alias, new X509CertificateEntry(NativeCertificate));
                }

                if (chain != null)
                {
                    foreach (var c in chain)
                    {
                        store.SetCertificateEntry(AliasOf(c),
                                                  new X509CertificateEntry(c.NativeCertificate));
                    }
                }
                using (var buff = new MemoryStream())
                {
                    store.Save(buff, password ?? new char[0], new SecureRandom());
                    return(buff.ToArray());
                }

            default:
                throw new NotSupportedException();
            }
        }
 public RecoverableSerialForm(PkiKey key)
 {
     _algorithm = key.Algorithm;
     _key       = key.Export(PkiEncodingFormat.Der);
     _isPrivate = key.IsPrivate;
 }