void signContent(MessageSigner messageSigner, Byte[] content) { hashAlgId = new AlgorithmIdentifier(messageSigner.HashingAlgorithm.ToOid(), new Byte[0]); pubKeyAlgId = new AlgorithmIdentifier(messageSigner.PublicKeyAlgorithm, new Byte[0]); prepareSigning(content); SignedContentBlob signedBlob; if (_authAttributes.Any()) { // auth attributes are encoded as IMPLICIT (OPTIONAL), but RFC2315 §9.3 requires signature computation for SET var attrBytes = _authAttributes.Encode(); attrBytes[0] = 0x31; signedBlob = new SignedContentBlob(attrBytes, ContentBlobType.ToBeSignedBlob); } else { if (content == null) { throw new ArgumentException("'content' parameter cannot be null if no authenticated attributes present."); } signedBlob = new SignedContentBlob(content, ContentBlobType.ToBeSignedBlob); } signerCert = new PkcsSubjectIdentifier(messageSigner.SignerCertificate, SubjectIdentifier); signedBlob.Sign(messageSigner); hashValue = signedBlob.Signature.Value; }
X509Certificate2 build(X509Certificate2 signer) { MessageSigner signerInfo = signer == null ? new MessageSigner(PrivateKeyInfo, HashingAlgorithm) : new MessageSigner(signer, HashingAlgorithm); signerInfo.PaddingScheme = AlternateSignatureFormat ? SignaturePadding.PSS : SignaturePadding.PKCS1; // initialize from v3 version var rawData = new List <Byte>(_versionBytes); // serial number rawData.AddRange(Asn1Utils.Encode(serialNumber, (Byte)Asn1Type.INTEGER)); // algorithm identifier rawData.AddRange(signerInfo.GetAlgorithmIdentifier(AlternateSignatureFormat).RawData); // issuer rawData.AddRange(signer == null ? SubjectName.RawData : signer.SubjectName.RawData); // NotBefore and NotAfter List <Byte> date = Asn1Utils.EncodeDateTime(NotBefore).ToList(); date.AddRange(Asn1Utils.EncodeDateTime(NotAfter)); rawData.AddRange(Asn1Utils.Encode(date.ToArray(), 48)); // subject rawData.AddRange(SubjectName.RawData); rawData.AddRange(PrivateKeyInfo.GetPublicKey().Encode()); rawData.AddRange(Asn1Utils.Encode(finalExtensions.Encode(), 0xa3)); var blob = new SignedContentBlob(Asn1Utils.Encode(rawData.ToArray(), 48), ContentBlobType.ToBeSignedBlob); blob.Sign(signerInfo); return(new X509Certificate2(blob.Encode())); }
/// <summary> /// Displays an X.509 certificate dump. /// </summary> /// <returns>Formatted string.</returns> public static String Format(this X509Certificate2 cert) { if (cert == null) { return(String.Empty); } var blob = new SignedContentBlob(cert.RawData, ContentBlobType.SignedBlob); String sigValue = AsnFormatter.BinaryToString(blob.Signature.Value.Reverse().ToArray(), EncodingType.HexAddress) .Replace(Environment.NewLine, Environment.NewLine + " "); var sb = new StringBuilder(); sb.Append($@"X509 Certificate: Version: {cert.Version} (0x{cert.Version - 1:x}) Serial Number: {cert.SerialNumber} {blob.SignatureAlgorithm} Issuer: {cert.IssuerName.FormatReverse(true).Replace(Environment.NewLine, Environment.NewLine + " ")} Name Hash(md5) : {getNameHash(cert.IssuerName, MD5.Create())} Name Hash(sha1) : {getNameHash(cert.IssuerName, SHA1.Create())} Name Hash(sha256) : {getNameHash(cert.IssuerName, SHA256.Create())} Valid From: {cert.NotBefore} Valid To : {cert.NotAfter} Subject: {cert.SubjectName.FormatReverse(true).Replace(Environment.NewLine, Environment.NewLine + " ")} Name Hash(md5) : {getNameHash(cert.SubjectName, MD5.Create())} Name Hash(sha1) : {getNameHash(cert.SubjectName, SHA1.Create())} Name Hash(sha256) : {getNameHash(cert.SubjectName, SHA256.Create())} {cert.PublicKey.Format().TrimEnd()} Certificate Extensions: {cert.Extensions.Count} {cert.Extensions.Format()} {blob.SignatureAlgorithm.ToString().TrimEnd()} Signature: UnusedBits={blob.Signature.UnusedBits} {sigValue} "); sb.AppendLine(cert.Issuer.Equals(cert.Subject, StringComparison.InvariantCultureIgnoreCase) ? "Root Certificate: Subject matches Issuer" : "Non-root Certificate"); sb.AppendLine($"Key Id Hash(sha1) : {getHashData(cert.PublicKey.Encode(), SHA1.Create())}"); sb.AppendLine($"Key Id Hash(rfc-md5) : {getHashData(cert.PublicKey.EncodedKeyValue.RawData, MD5.Create())}"); sb.AppendLine($"Key Id Hash(rfc-sha1) : {getHashData(cert.PublicKey.EncodedKeyValue.RawData, SHA1.Create())}"); sb.AppendLine($"Key Id Hash(rfc-sha256) : {getHashData(cert.PublicKey.EncodedKeyValue.RawData, SHA256.Create())}"); sb.AppendLine($"Key Id Hash(pin-sha256-b64) : {getKeyPinHash(cert.PublicKey, SHA256.Create())}"); sb.AppendLine($"Key Id Hash(pin-sha256-hex) : {getHashData(cert.PublicKey.Encode(), SHA256.Create())}"); sb.AppendLine($"Cert Hash(md5) : {getCertHash(cert, MD5.Create())}"); sb.AppendLine($"Cert Hash(sha1) : {getCertHash(cert, SHA1.Create())}"); sb.AppendLine($"Cert Hash(sha256) : {getCertHash(cert, SHA256.Create())}"); sb.AppendLine($"Signature Hash : {getHashData(blob.GetRawSignature(), SHA1.Create())}"); return(sb.ToString()); }
/// <summary> /// Verifies whether the specified certificate is an issuer of this CRL by verifying CRL signature /// against specified certificate's public key. /// </summary> /// <param name="issuer"> /// A potential issuer's certificate. /// </param> /// <param name="strict"> /// Specifies whether to perform CRL issuer and certificate's subject name binary comparison. /// </param> /// <exception cref="CryptographicException"> /// The data is invalid. /// </exception> /// <exception cref="UninitializedObjectException">An object is not initialized.</exception> /// <returns> /// <strong>True</strong> if the specified certificate is signed this CRL. Otherwise <strong>False</strong>. /// </returns> public Boolean VerifySignature(X509Certificate2 issuer, Boolean strict = false) { if (RawData == null) { throw new UninitializedObjectException(); } var signedInfo = new SignedContentBlob(RawData, ContentBlobType.SignedBlob); return(MessageSigner.VerifyData(signedInfo, issuer.PublicKey)); }
/// <summary> /// Hashes and encodes CRL object from builder information. Instead of signing, CRL is hashed. /// </summary> /// <param name="hasherInfo"> /// Issuer certificate to use as a CRL issuer. Issuer certificate is not required to have private key. /// </param> /// <returns>An instance of generated CRL object.</returns> public X509CRL2 BuildAndHash(X509Certificate2 hasherInfo) { var dummyBlob = new SignedContentBlob(new Byte[] { 0 }, ContentBlobType.ToBeSignedBlob); dummyBlob.Hash(new Oid2(HashingAlgorithm, false)); List <Byte> tbs = buildTbs(dummyBlob.SignatureAlgorithm.RawData, hasherInfo); var blob = new SignedContentBlob(tbs.ToArray(), ContentBlobType.ToBeSignedBlob); blob.Hash(new Oid2(HashingAlgorithm, false)); return(new X509CRL2(blob.Encode())); }
/// <summary> /// Signs and encodes CRL object from builder information. /// </summary> /// <param name="signerInfo">Certificate which is used to sign CRL.</param> /// <returns>An instance of generated signed CRL object.</returns> public X509CRL2 BuildAndSign(MessageSigner signerInfo) { if (signerInfo == null) { throw new ArgumentNullException(nameof(signerInfo)); } // create dummy blob, sign/hash it to get proper encoded signature algorithm identifier. var dummyBlob = new SignedContentBlob(new Byte[] { 0 }, ContentBlobType.ToBeSignedBlob); dummyBlob.Sign(signerInfo); // generate tbs List <Byte> tbs = buildTbs(dummyBlob.SignatureAlgorithm.RawData, signerInfo.SignerCertificate); // now create correct blob and sign/hash it var blob = new SignedContentBlob(tbs.ToArray(), ContentBlobType.ToBeSignedBlob); blob.Sign(signerInfo); return(new X509CRL2(blob.Encode())); }
/// <summary> /// Verifies signature of a signed blob by using specified public key. /// </summary> /// <param name="blob"></param> /// <param name="publicKey"></param> /// <returns></returns> /// <remarks> /// This method is suitable to validate certificate signing requests (CSR) or other data /// when signing key pair exist outside of X.509 certificate object. /// </remarks> public static Boolean VerifyData(SignedContentBlob blob, PublicKey publicKey) { if (blob == null) { throw new ArgumentNullException(nameof(blob)); } if (publicKey == null) { throw new ArgumentNullException(nameof(publicKey)); } if (blob.BlobType != ContentBlobType.SignedBlob) { throw new InvalidOperationException("The blob is not signed."); } using (var signerInfo = new MessageSigner()) { signerInfo.acquirePublicKey(publicKey); signerInfo.getConfiguration(blob.SignatureAlgorithm.RawData); return(signerInfo.VerifyData(blob.ToBeSignedData, blob.GetRawSignature())); } }
/// <summary> /// Gets decoded textual representation (dump) of the current object. /// </summary> /// <returns>Textual representation of the current object.</returns> public virtual String Format() { var SB = new StringBuilder(); var blob = new SignedContentBlob(RawData, ContentBlobType.SignedBlob); SB.Append( $@"PKCS10 Certificate Request: Version: {Version} Subject: {Subject ?? "EMPTY"} {PublicKey.Format().TrimEnd()} Request attributes (Count={Attributes.Count}):{formatAttributes().TrimEnd()} Request extensions (Count={Extensions.Count}):{formatExtensions().TrimEnd()} {blob.SignatureAlgorithm.ToString().TrimEnd()} Signature: Unused bits={blob.Signature.UnusedBits} {AsnFormatter.BinaryToString(blob.Signature.Value.ToArray(), EncodingType.HexAddress).Replace("\r\n", "\r\n ")} Signature matches Public Key: {SignatureIsValid} "); return(SB.ToString()); }
/// <summary> /// Populates current object with data from ASN.1-encoded byte array that represents encoded PKCS#10 /// certificate request. /// </summary> /// <param name="rawData">ASN.1-encoded byte array.</param> /// <exception cref="ArgumentNullException"><strong>rawData</strong> parameter is null.</exception> protected void Decode(Byte[] rawData) { if (rawData == null) { throw new ArgumentNullException(nameof(rawData)); } var blob = new SignedContentBlob(rawData, ContentBlobType.SignedBlob); // at this point we can set signature algorithm and populate RawData SignatureAlgorithm = blob.SignatureAlgorithm.AlgorithmId; Asn1Reader asn = new Asn1Reader(blob.ToBeSignedData); getVersion(asn); getSubject(asn); getPublicKey(asn); // if we reach this far, then we can verify request attribute. SignatureIsValid = MessageSigner.VerifyData(blob, PublicKey); asn.MoveNextCurrentLevel(); if (asn.Tag == 0xa0) { getAttributes(asn); } RawData = rawData; }
void m_decode(Byte[] rawData) { try { Type = X509CrlType.BaseCrl; var signedInfo = new SignedContentBlob(rawData, ContentBlobType.SignedBlob); // signature and alg signature = signedInfo.Signature.Value; sigUnused = signedInfo.Signature.UnusedBits; SignatureAlgorithm = signedInfo.SignatureAlgorithm.AlgorithmId; // tbs Asn1Reader asn = new Asn1Reader(signedInfo.ToBeSignedData); if (!asn.MoveNext()) { throw new Asn1InvalidTagException(); } // version if (asn.Tag == (Byte)Asn1Type.INTEGER) { Version = (Int32)Asn1Utils.DecodeInteger(asn.GetTagRawData()) + 1; asn.MoveNextCurrentLevel(); } else { Version = 1; } // hash algorithm var h = new AlgorithmIdentifier(asn.GetTagRawData()); if (h.AlgorithmId.Value != SignatureAlgorithm.Value) { throw new CryptographicException("Algorithm mismatch."); } if (!asn.MoveNextCurrentLevel()) { throw new Asn1InvalidTagException(); } // issuer IssuerName = new X500DistinguishedName(asn.GetTagRawData()); // NextUpdate, RevokedCerts and Extensions are optional. Ref: RFC5280, p.118 if (!asn.MoveNextCurrentLevel()) { throw new Asn1InvalidTagException(); } switch (asn.Tag) { case (Byte)Asn1Type.UTCTime: ThisUpdate = Asn1Utils.DecodeUTCTime(asn.GetTagRawData()); break; case (Byte)Asn1Type.Generalizedtime: ThisUpdate = Asn1Utils.DecodeGeneralizedTime(asn.GetTagRawData()); break; default: throw new Asn1InvalidTagException(); } if (!asn.MoveNextCurrentLevel()) { return; } switch (asn.Tag) { case (Byte)Asn1Type.UTCTime: case (Byte)Asn1Type.Generalizedtime: switch (asn.Tag) { case (Byte)Asn1Type.UTCTime: NextUpdate = Asn1Utils.DecodeUTCTime(asn.GetTagRawData()); break; case (Byte)Asn1Type.Generalizedtime: NextUpdate = Asn1Utils.DecodeGeneralizedTime(asn.GetTagRawData()); break; default: throw new Asn1InvalidTagException(); } if (!asn.MoveNextCurrentLevel()) { return; } if (asn.Tag == 48) { getRevCerts(asn); if (!asn.MoveNextCurrentLevel()) { return; } getExts(asn); } else { getExts(asn); } break; case 48: if (asn.Tag == 48) { getRevCerts(asn); if (!asn.MoveNextCurrentLevel()) { return; } getExts(asn); } else { getExts(asn); } break; default: getExts(asn); break; } } catch (Exception e) { throw new CryptographicException("Cannot find the requested object.", e); } }
/// <summary> /// Verifies whether the specified certificate is an issuer of this CRL by verifying CRL signature /// against specified certificate's public key. /// </summary> /// <param name="issuer"> /// A potential issuer's certificate. /// </param> /// <param name="strict"> /// Specifies whether to perform CRL issuer and certificate's subject name binary comparison. This parameter is not implemented. /// </param> /// <exception cref="CryptographicException"> /// The data is invalid. /// </exception> /// <returns> /// <strong>True</strong> if the specified certificate is signed this CRL. Otherwise <strong>False</strong>. /// </returns> public Boolean VerifySignature(X509Certificate2 issuer, Boolean strict = false) { var signedInfo = new SignedContentBlob(_rawData, ContentBlobType.SignedBlob); return(MessageSigner.VerifyData(signedInfo, issuer.PublicKey)); }