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