public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) { _oid = new Oid (oid, friendlyName); base.Critical = critical; _keyUsages = GetValidFlags (keyUsages); RawData = Encode (); }
public unsafe void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages) { using (SafeAsn1BitStringHandle bitString = Interop.libcrypto.OpenSslD2I(Interop.libcrypto.d2i_ASN1_BIT_STRING, encoded)) { Interop.libcrypto.CheckValidOpenSslHandle(bitString); byte[] decoded = Interop.NativeCrypto.GetAsn1StringBytes(bitString.DangerousGetHandle()); // Only 9 bits are defined. if (decoded.Length > 2) { throw new CryptographicException(); } // DER encodings of BIT_STRING values number the bits as // 01234567 89 (big endian), plus a number saying how many bits of the last byte were padding. // // So digitalSignature (0) doesn't mean 2^0 (0x01), it means the most significant bit // is set in this byte stream. // // BIT_STRING values are compact. So a value of cRLSign (6) | keyEncipherment (2), which // is 0b0010001 => 0b0010 0010 (1 bit padding) => 0x22 encoded is therefore // 0x02 (length remaining) 0x01 (1 bit padding) 0x22. // // OpenSSL's d2i_ASN1_BIT_STRING is going to take that, and return 0x22. 0x22 lines up // exactly with X509KeyUsageFlags.CrlSign (0x20) | X509KeyUsageFlags.KeyEncipherment (0x02) // // Once the decipherOnly (8) bit is added to the mix, the values become: // 0b001000101 => 0b0010 0010 1000 0000 (7 bits padding) // { 0x03 0x07 0x22 0x80 } // And OpenSSL returns new byte[] { 0x22 0x80 } // // The value of X509KeyUsageFlags.DecipherOnly is 0x8000. 0x8000 in a little endian // representation is { 0x00 0x80 }. This means that the DER storage mechanism has effectively // ended up being little-endian for BIT_STRING values. Untwist the bytes, and now the bits all // line up with the existing X509KeyUsageFlags. int value = 0; if (decoded.Length > 0) { value = decoded[0]; } if (decoded.Length > 1) { value |= decoded[1] << 8; } keyUsages = (X509KeyUsageFlags)value; } }
private X509CertificateKeyUsage(X509KeyUsageFlags keyUsage, string description) { if (Map == null) { Map = new Dictionary<X509KeyUsageFlags, X509CertificateKeyUsage>(); } KeyUsage = keyUsage; Description = description; Map[KeyUsage] = this; }
private static unsafe byte[] EncodeExtension(X509KeyUsageFlags keyUsages) { CAPIBase.CRYPT_BIT_BLOB crypt_bit_blob = new CAPIBase.CRYPT_BIT_BLOB { cbData = 2, pbData = new IntPtr((void*) &keyUsages), cUnusedBits = 0 }; byte[] encodedData = null; if (!CAPI.EncodeObject("2.5.29.15", new IntPtr((void*) &crypt_bit_blob), out encodedData)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } return encodedData; }
public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages) { unsafe { ushort keyUsagesAsShort = (ushort)keyUsages; CRYPT_BIT_BLOB blob = new CRYPT_BIT_BLOB() { cbData = 2, pbData = (byte*)&keyUsagesAsShort, cUnusedBits = 0, }; return Interop.crypt32.EncodeObject(CryptDecodeObjectStructType.X509_KEY_USAGE, &blob); } }
/// <summary> /// Verify RSA key pair of two certificates. /// </summary> public static bool VerifyRSAKeyPair( X509Certificate2 certWithPublicKey, X509Certificate2 certWithPrivateKey, bool throwOnError = false) { bool result = false; RSA rsaPrivateKey = null; RSA rsaPublicKey = null; try { // verify the public and private key match rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey(); rsaPublicKey = certWithPublicKey.GetRSAPublicKey(); X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey); if ((keyUsage & X509KeyUsageFlags.DataEncipherment) != 0) { result = VerifyRSAKeyPairCrypt(rsaPublicKey, rsaPrivateKey); } else if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0) { result = VerifyRSAKeyPairSign(rsaPublicKey, rsaPrivateKey); } else { throw new CryptographicException("Don't know how to verify the public/private key pair."); } } catch (Exception e) { if (throwOnError) { throw e; } } finally { RsaUtils.RSADispose(rsaPrivateKey); RsaUtils.RSADispose(rsaPublicKey); if (!result && throwOnError) { throw new CryptographicException("The public/private key pair in the certficates do not match."); } } return(result); }
public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages) { // The numeric values of X509KeyUsageFlags mean that if we interpret it as a little-endian // ushort it will line up with the flags in the spec. ushort ushortValue = unchecked ((ushort)(int)keyUsages); byte[] data = BitConverter.GetBytes(ushortValue); // RFC 3280 section 4.2.1.3 (https://tools.ietf.org/html/rfc3280#section-4.2.1.3) defines // digitalSignature (0) through decipherOnly (8), making 9 named bits. const int namedBitsCount = 9; // The expected output of this method isn't the SEQUENCE value, but just the payload bytes. byte[][] segments = DerEncoder.SegmentedEncodeNamedBitList(data, namedBitsCount); Debug.Assert(segments.Length == 3); return(ConcatenateArrays(segments)); }
public static bool IsForUsage(this X509Certificate2 certificate, X509KeyUsageFlags usageFlag) { ThrowHelpers.CheckNull(nameof(certificate), certificate); foreach (X509Extension certificateExtension in certificate.Extensions) { if (certificateExtension is X509KeyUsageExtension usage) { if (usage.KeyUsages.HasFlag(usageFlag)) { return(true); } } } return(false); }
public X509Certificate2 NewECDsaSelfSignedCertificate( BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, CertificateRequest request) { X509Certificate2 generatedCertificate = SelfSignedConfiguration( basicConstraints, validityPeriod, subjectAlternativeName, enhancedKeyUsages, x509KeyUsageFlags, request); return(generatedCertificate); }
public void FindByKeyUsage(X509KeyUsageFlags keyUsage) { FindCore( cert => { X509Extension ext = FindExtension(cert, Oids.KeyUsage); if (ext == null) { // A certificate with no key usage extension is considered valid for all key usages. return(true); } var kuExt = (X509KeyUsageExtension)ext; return((kuExt.KeyUsages & keyUsage) == keyUsage); }); }
private static string CreateCert(string cn, X509KeyUsageFlags usage) { using var algo = RSA.Create(keySizeInBits: 4096); var request = new CertificateRequest( new X500DistinguishedName($"CN={cn}"), algo, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1 ); request.CertificateExtensions.Add( new X509KeyUsageExtension(usage, critical: true) ); var cert = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(4)); var data = cert.Export(X509ContentType.Pfx, string.Empty); return(Convert.ToBase64String(data)); }
public virtual void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages) { KeyUsageFlagsAsn keyUsagesAsn; try { AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER); keyUsagesAsn = reader.ReadNamedBitListValue <KeyUsageFlagsAsn>(); reader.ThrowIfNotEmpty(); } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } // DER encodings of BIT_STRING values number the bits as // 01234567 89 (big endian), plus a number saying how many bits of the last byte were padding. // // So digitalSignature (0) doesn't mean 2^0 (0x01), it means the most significant bit // is set in this byte stream. // // BIT_STRING values are compact. So a value of cRLSign (6) | keyEncipherment (2), which // is 0b0010001 => 0b0010 0010 (1 bit padding) => 0x22 encoded is therefore // 0x02 (length remaining) 0x01 (1 bit padding) 0x22. // // We will read that, and return 0x22. 0x22 lines up // exactly with X509KeyUsageFlags.CrlSign (0x20) | X509KeyUsageFlags.KeyEncipherment (0x02) // // Once the decipherOnly (8) bit is added to the mix, the values become: // 0b001000101 => 0b0010 0010 1000 0000 (7 bits padding) // { 0x03 0x07 0x22 0x80 } // And we read new byte[] { 0x22 0x80 } // // The value of X509KeyUsageFlags.DecipherOnly is 0x8000. 0x8000 in a little endian // representation is { 0x00 0x80 }. This means that the DER storage mechanism has effectively // ended up being little-endian for BIT_STRING values. Untwist the bytes, and now the bits all // line up with the existing X509KeyUsageFlags. keyUsages = (X509KeyUsageFlags)ReverseBitOrder((byte)keyUsagesAsn) | (X509KeyUsageFlags)(ReverseBitOrder((byte)(((ushort)keyUsagesAsn >> 8))) << 8); }
public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages) { unsafe { uint keyUsagesAsUint = 0; encoded.DecodeObject( CryptDecodeObjectStructType.X509_KEY_USAGE, delegate(void *pvDecoded) { CRYPT_BIT_BLOB *pBlob = (CRYPT_BIT_BLOB *)pvDecoded; keyUsagesAsUint = 0; if (pBlob->pbData != null) { keyUsagesAsUint = *(uint *)(pBlob->pbData); } } ); keyUsages = (X509KeyUsageFlags)keyUsagesAsUint; } }
public static bool IsForUsage(this X509Certificate2 certificate, X509KeyUsageFlags usageFlag) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } foreach (X509Extension certificateExtension in certificate.Extensions) { if (certificateExtension is X509KeyUsageExtension usage) { if (usage.KeyUsages.HasFlag(usageFlag)) { return(true); } } } return(false); }
public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages) { unsafe { uint keyUsagesAsUint = 0; encoded.DecodeObject( CryptDecodeObjectStructType.X509_KEY_USAGE, delegate (void* pvDecoded) { CRYPT_BIT_BLOB* pBlob = (CRYPT_BIT_BLOB*)pvDecoded; keyUsagesAsUint = 0; if (pBlob->pbData != null) { keyUsagesAsUint = *(uint*)(pBlob->pbData); } } ); keyUsages = (X509KeyUsageFlags)keyUsagesAsUint; } }
/// <summary> /// Verify ECDsa key pair of two certificates. /// </summary> public static bool VerifyECDsaKeyPair( X509Certificate2 certWithPublicKey, X509Certificate2 certWithPrivateKey, bool throwOnError = false) { bool result = false; using (ECDsa ecdsaPublicKey = certWithPrivateKey.GetECDsaPublicKey()) using (ECDsa ecdsaPrivateKey = certWithPublicKey.GetECDsaPrivateKey()) { try { // verify the public and private key match X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey); if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0) { result = VerifyECDsaKeyPairSign(ecdsaPublicKey, ecdsaPrivateKey); } else { if (throwOnError) { throw new CryptographicException("Don't know how to verify the public/private key pair."); } } } catch (Exception) { if (throwOnError) { throwOnError = false; throw; } } } if (!result && throwOnError) { throw new CryptographicException("The public/private key pair in the certficates do not match."); } return(result); }
internal AsnDecodeStatus Decode(byte[] extension) { if ((extension == null) || (extension.Length == 0)) { return(AsnDecodeStatus.BadAsn); } if (extension [0] != 0x03) { return(AsnDecodeStatus.BadTag); } if (extension.Length < 3) { return(AsnDecodeStatus.BadLength); } if (extension.Length < 4) { return(AsnDecodeStatus.InformationNotAvailable); } try { ASN1 ex = new ASN1(extension); int kubits = 0; int i = 1; // byte zero has the number of unused bits (ASN1's BITSTRING) while (i < ex.Value.Length) { kubits = (kubits << 8) + ex.Value [i++]; } _keyUsages = GetValidFlags((X509KeyUsageFlags)kubits); } catch { return(AsnDecodeStatus.BadAsn); } return(AsnDecodeStatus.Ok); }
public X509Certificate2 NewRsaSelfSignedCertificate( DistinguishedName distinguishedName, BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, RsaConfiguration rsaConfiguration) { using var rsa = RSA.Create(rsaConfiguration.KeySize); // 1024, 2048 or 4096 var request = new CertificateRequest( _certificateUtility.CreateIssuerOrSubject(distinguishedName), rsa, rsaConfiguration.HashAlgorithmName, rsaConfiguration.RSASignaturePadding); return(NewRsaSelfSignedCertificate(basicConstraints, validityPeriod, subjectAlternativeName, enhancedKeyUsages, x509KeyUsageFlags, request)); }
/// <summary> /// Create a Self signed certificate with all options which can also be used as a root certificate /// </summary> /// <param name="distinguishedName">Distinguished Name used for the subject and the issuer properties</param> /// <param name="validityPeriod">Valid from, Valid to certificate properties</param> /// <param name="subjectAlternativeName">SAN but only DnsNames can be added as a list + Email property</param> /// <param name="enhancedKeyUsages">Defines how the certificate key can be used. /// OidLookup.ServerAuthentication, /// OidLookup.ClientAuthentication, /// OidLookup.CodeSigning, /// OidLookup.SecureEmail, /// OidLookup.TimeStamping /// </param> /// <param name="x509KeyUsageFlags">Defines how the certificate key can be used. /// None No key usage parameters. /// EncipherOnly The key can be used for encryption only. /// CrlSign The key can be used to sign a certificate revocation list (CRL). /// KeyCertSign The key can be used to sign certificates. /// KeyAgreement The key can be used to determine key agreement, such as a key created using the Diffie-Hellman key agreement algorithm. /// DataEncipherment The key can be used for data encryption. /// KeyEncipherment The key can be used for key encryption. /// NonRepudiation The key can be used for authentication. /// DecipherOnly The key can be used for decryption only. /// </param> /// <returns>Self signed certificate</returns> public X509Certificate2 NewECDsaSelfSignedCertificate( DistinguishedName distinguishedName, BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, ECDsaConfiguration eCDsaConfiguration) { using var ecdsa = ECDsa.Create("ECDsa"); ecdsa.KeySize = eCDsaConfiguration.KeySize; var request = new CertificateRequest( _certificateUtility.CreateIssuerOrSubject(distinguishedName), ecdsa, eCDsaConfiguration.HashAlgorithmName); return(NewECDsaSelfSignedCertificate(basicConstraints, validityPeriod, subjectAlternativeName, enhancedKeyUsages, x509KeyUsageFlags, request)); }
public X509Certificate2 NewECDsaChainedCertificate( BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, X509Certificate2 signingCertificate, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, CertificateRequest request, ECDsa ecdsa) { if (signingCertificate == null) { throw new ArgumentNullException(nameof(signingCertificate)); } if (!signingCertificate.HasPrivateKey) { throw new Exception("Signing cert must have private key"); } X509Certificate2 cert = ChainedConfiguration( basicConstraints, validityPeriod, subjectAlternativeName, signingCertificate, enhancedKeyUsages, x509KeyUsageFlags, request); if (ecdsa == null) { return(cert); } else { return(cert.CopyWithPrivateKey(ecdsa)); } }
public X509Certificate2 NewRsaChainedCertificate( DistinguishedName distinguishedName, BasicConstraints basicConstraints, ValidityPeriod validityPeriod, SubjectAlternativeName subjectAlternativeName, X509Certificate2 signingCertificate, OidCollection enhancedKeyUsages, X509KeyUsageFlags x509KeyUsageFlags, RsaConfiguration rsaConfiguration) { if (signingCertificate == null) { throw new ArgumentNullException(nameof(signingCertificate)); } if (!signingCertificate.HasPrivateKey) { throw new Exception("Signing cert must have private key"); } using var rsa = RSA.Create(rsaConfiguration.KeySize); var request = new CertificateRequest( _certificateUtility.CreateIssuerOrSubject(distinguishedName), rsa, rsaConfiguration.HashAlgorithmName, rsaConfiguration.RSASignaturePadding); X509Certificate2 cert = ChainedConfiguration( basicConstraints, validityPeriod, subjectAlternativeName, signingCertificate, enhancedKeyUsages, x509KeyUsageFlags, request); return(cert.CopyWithPrivateKey(rsa)); }
private static CertificateRequest CreateChainRequest( string dn, AsymmetricAlgorithm key, HashAlgorithmName hashAlgorithm, bool isCa, int?pathLen) { const X509KeyUsageFlags CAFlags = X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign; const X509KeyUsageFlags EEFlags = X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation; CertificateRequest request = OpenCertRequest(dn, key, hashAlgorithm); request.CertificateExtensions.Add( new X509SubjectKeyIdentifierExtension( request.PublicKey, X509SubjectKeyIdentifierHashAlgorithm.Sha1, false)); request.CertificateExtensions.Add( new X509KeyUsageExtension( isCa ? CAFlags : EEFlags, true)); request.CertificateExtensions.Add( new X509BasicConstraintsExtension( isCa, pathLen.HasValue, pathLen.GetValueOrDefault(), true)); return(request); }
public X509Certificate2Collection Find(X509FindType findType, object findValue, bool validOnly) { if (findValue == null) { throw new ArgumentNullException("findValue"); } string str = String.Empty; string oid = String.Empty; X509KeyUsageFlags ku = X509KeyUsageFlags.None; DateTime dt = DateTime.MinValue; switch (findType) { case X509FindType.FindByThumbprint: case X509FindType.FindBySubjectName: case X509FindType.FindBySubjectDistinguishedName: case X509FindType.FindByIssuerName: case X509FindType.FindByIssuerDistinguishedName: case X509FindType.FindBySerialNumber: case X509FindType.FindByTemplateName: case X509FindType.FindBySubjectKeyIdentifier: try { str = (string)findValue; } catch (Exception e) { string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.", findValue.GetType(), "string"); throw new CryptographicException(msg, e); } break; case X509FindType.FindByApplicationPolicy: case X509FindType.FindByCertificatePolicy: case X509FindType.FindByExtension: try { oid = (string)findValue; } catch (Exception e) { string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.", findValue.GetType(), "X509KeyUsageFlags"); throw new CryptographicException(msg, e); } // OID validation try { CryptoConfig.EncodeOID(oid); } catch (CryptographicUnexpectedOperationException) { string msg = Locale.GetText("Invalid OID value '{0}'.", oid); throw new ArgumentException("findValue", msg); } break; case X509FindType.FindByKeyUsage: try { ku = (X509KeyUsageFlags)findValue; } catch (Exception e) { string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.", findValue.GetType(), "X509KeyUsageFlags"); throw new CryptographicException(msg, e); } break; case X509FindType.FindByTimeValid: case X509FindType.FindByTimeNotYetValid: case X509FindType.FindByTimeExpired: try { dt = (DateTime)findValue; } catch (Exception e) { string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.", findValue.GetType(), "X509DateTime"); throw new CryptographicException(msg, e); } break; default: { string msg = Locale.GetText("Invalid find type '{0}'.", findType); throw new CryptographicException(msg); } } CultureInfo cinv = CultureInfo.InvariantCulture; X509Certificate2Collection results = new X509Certificate2Collection(); foreach (X509Certificate2 x in InnerList) { bool value_match = false; switch (findType) { case X509FindType.FindByThumbprint: // works with Thumbprint, GetCertHashString in both normal (upper) and lower case value_match = ((String.Compare(str, x.Thumbprint, true, cinv) == 0) || (String.Compare(str, x.GetCertHashString(), true, cinv) == 0)); break; case X509FindType.FindBySubjectName: string [] names = x.SubjectName.Format(true).Split(newline_split, StringSplitOptions.RemoveEmptyEntries); foreach (string name in names) { int pos = name.IndexOf('='); value_match = (name.IndexOf(str, pos, StringComparison.InvariantCultureIgnoreCase) >= 0); if (value_match) { break; } } break; case X509FindType.FindBySubjectDistinguishedName: value_match = (String.Compare(str, x.Subject, true, cinv) == 0); break; case X509FindType.FindByIssuerName: string iname = x.GetNameInfo(X509NameType.SimpleName, true); value_match = (iname.IndexOf(str, StringComparison.InvariantCultureIgnoreCase) >= 0); break; case X509FindType.FindByIssuerDistinguishedName: value_match = (String.Compare(str, x.Issuer, true, cinv) == 0); break; case X509FindType.FindBySerialNumber: value_match = (String.Compare(str, x.SerialNumber, true, cinv) == 0); break; case X509FindType.FindByTemplateName: // TODO - find a valid test case break; case X509FindType.FindBySubjectKeyIdentifier: value_match = (String.Compare(str, GetKeyIdentifier(x), true, cinv) == 0); break; case X509FindType.FindByApplicationPolicy: // note: include when no extensions are present (even if v3) value_match = (x.Extensions.Count == 0); // TODO - find test case with extension break; case X509FindType.FindByCertificatePolicy: // TODO - find test case with extension break; case X509FindType.FindByExtension: value_match = (x.Extensions [oid] != null); break; case X509FindType.FindByKeyUsage: X509KeyUsageExtension kue = (x.Extensions ["2.5.29.15"] as X509KeyUsageExtension); if (kue == null) { // key doesn't have any hard coded limitations // note: MS doesn't check for ExtendedKeyUsage value_match = true; } else { value_match = ((kue.KeyUsages & ku) == ku); } break; case X509FindType.FindByTimeValid: value_match = ((dt >= x.NotBefore) && (dt <= x.NotAfter)); break; case X509FindType.FindByTimeNotYetValid: value_match = (dt < x.NotBefore); break; case X509FindType.FindByTimeExpired: value_match = (dt > x.NotAfter); break; } if (!value_match) { continue; } if (validOnly) { try { if (x.Verify()) { results.Add(x); } } catch { } } else { results.Add(x); } } return(results); }
public static void ChainCertRequirements(bool useIntermed, bool?isCA, X509KeyUsageFlags keyUsage, bool expectSuccess) { HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA384; ECDsa rootKey = null; ECDsa intermedKey = null; ECDsa leafKey = null; X509Certificate2 rootCert = null; X509Certificate2 intermedCert = null; X509Certificate2 leafCert = null; try { rootKey = ECDsa.Create(ECCurve.NamedCurves.nistP384); var request = new CertificateRequest("CN=Root", rootKey, hashAlgorithm); if (useIntermed || isCA.HasValue) { request.CertificateExtensions.Add( new X509BasicConstraintsExtension(useIntermed || isCA.Value, false, 0, true)); } X509KeyUsageFlags rootFlags = useIntermed ? X509KeyUsageFlags.KeyCertSign : keyUsage; if (rootFlags != X509KeyUsageFlags.None) { request.CertificateExtensions.Add(new X509KeyUsageExtension(rootFlags, true)); } DateTimeOffset start = DateTimeOffset.UtcNow.AddHours(-1); DateTimeOffset end = start.AddHours(2); rootCert = request.CreateSelfSigned(start, end); X509Certificate2 signerCert = rootCert; if (useIntermed) { intermedKey = ECDsa.Create(ECCurve.NamedCurves.nistP384); request = new CertificateRequest("CN=Intermediate", intermedKey, hashAlgorithm); if (isCA.HasValue) { request.CertificateExtensions.Add( new X509BasicConstraintsExtension(isCA.Value, false, 0, true)); } if (keyUsage != X509KeyUsageFlags.None) { request.CertificateExtensions.Add(new X509KeyUsageExtension(keyUsage, true)); } using (X509Certificate2 tmp = request.Create(rootCert, start, end, new byte[] { 6, 0, 2, 2, 10, 23 })) { intermedCert = tmp.CopyWithPrivateKey(intermedKey); } signerCert = intermedCert; } leafKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); request = new CertificateRequest("CN=Leaf", leafKey, hashAlgorithm); byte[] leafSerialNumber = { 2, 4, 6, 0, 1 }; if (!expectSuccess) { AssertExtensions.Throws <ArgumentException>( "issuerCertificate", () => { request.Create(signerCert, start, end, leafSerialNumber)?.Dispose(); }); return; } leafCert = request.Create(signerCert, start, end, leafSerialNumber); using (X509Chain chain = new X509Chain()) { chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; chain.ChainPolicy.ExtraStore.Add(rootCert); chain.ChainPolicy.VerificationTime = start.ToLocalTime().DateTime; if (useIntermed) { chain.ChainPolicy.ExtraStore.Add(intermedCert); } RunChain(chain, leafCert, true, "Chain verification"); DisposeChainCerts(chain); } } finally { leafCert?.Dispose(); leafKey?.Dispose(); intermedCert?.Dispose(); intermedKey?.Dispose(); rootCert?.Dispose(); rootKey?.Dispose(); } }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) : base(Oids.KeyUsage, X509Pal.Instance.EncodeX509KeyUsageExtension(keyUsages), critical) { }
public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) : base (CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) {}
public static void TraceAndLog(string subject, string thumbPrint, X509KeyUsageFlags keyUsage) { DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information, EventLogCategory.Wsat, (EventLogEventId) (-1073545195), new string[] { subject, thumbPrint, keyUsage.ToString() }); }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical);
private StorePal CreatedLinkedStoreWithFindResults(X509FindType findType, Object findValue, bool validOnly) { unsafe { switch (findType) { case X509FindType.FindByThumbprint: { byte[] thumbPrint = ConfirmedCast <String>(findValue).DecodeHexString(); fixed(byte *pThumbPrint = thumbPrint) { CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(thumbPrint.Length, pThumbPrint); return(FindCore(CertFindType.CERT_FIND_HASH, &blob, validOnly)); } } case X509FindType.FindBySubjectName: { String subjectName = ConfirmedCast <String>(findValue); fixed(char *pSubjectName = subjectName) { return(FindCore(CertFindType.CERT_FIND_SUBJECT_STR, pSubjectName, validOnly)); } } case X509FindType.FindBySubjectDistinguishedName: { String subjectDistinguishedName = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.None); return subjectDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase); } )); } case X509FindType.FindByIssuerName: { String issuerName = ConfirmedCast <String>(findValue); fixed(char *pIssuerName = issuerName) { return(FindCore(CertFindType.CERT_FIND_ISSUER_STR, pIssuerName, validOnly)); } } case X509FindType.FindByIssuerDistinguishedName: { String issuerDistinguishedName = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.CERT_NAME_ISSUER_FLAG); return issuerDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase); } )); } case X509FindType.FindBySerialNumber: { String decimalOrHexString = ConfirmedCast <String>(findValue); // FindBySerialNumber allows the input format to be either in hex or decimal. Since we can't know which one was intended, // it compares against both interpretations and treats a match of either as a successful find. byte[] hexBytes = decimalOrHexString.DecodeHexString(); Array.Reverse(hexBytes); // String is big-endian, BigInteger constructor requires little-endian. BigInteger expected1 = PositiveBigIntegerFromByteArray(hexBytes); BigInteger ten = new BigInteger(10); BigInteger expected2 = BigInteger.Zero; foreach (char c in decimalOrHexString) { if (c >= '0' && c <= '9') { expected2 = BigInteger.Multiply(expected2, ten); expected2 = BigInteger.Add(expected2, c - '0'); } } return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { byte[] actual = pCertContext.CertContext->pCertInfo->SerialNumber.ToByteArray(); BigInteger actualAsBigInteger = PositiveBigIntegerFromByteArray(actual); // Convert to BigInteger as the comparison must not fail due to spurious leading zeros GC.KeepAlive(pCertContext); return expected1.Equals(actualAsBigInteger) || expected2.Equals(actualAsBigInteger); } )); } case X509FindType.FindByTimeValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == 0; } )); } case X509FindType.FindByTimeNotYetValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == -1; } )); } case X509FindType.FindByTimeExpired: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == 1; } )); } case X509FindType.FindByTemplateName: { String expected = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { // The template name can have 2 different formats: V1 format (<= Win2K) is just a string // V2 format (XP only) can be a friendly name or an OID. // An example of Template Name can be "ClientAuth". bool foundMatch = false; CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; { CERT_EXTENSION *pV1Template = Interop.crypt32.CertFindExtension(Oids.EnrollCertTypeExtension, pCertInfo->cExtension, pCertInfo->rgExtension); if (pV1Template != null) { byte[] extensionRawData = pV1Template->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_UNICODE_ANY_STRING, delegate(void *pvDecoded) { CERT_NAME_VALUE *pNameValue = (CERT_NAME_VALUE *)pvDecoded; String actual = Marshal.PtrToStringUni(new IntPtr(pNameValue->Value.pbData)); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; } })) { return false; } } } if (!foundMatch) { CERT_EXTENSION *pV2Template = Interop.crypt32.CertFindExtension(Oids.CertificateTemplate, pCertInfo->cExtension, pCertInfo->rgExtension); if (pV2Template != null) { byte[] extensionRawData = pV2Template->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_CERTIFICATE_TEMPLATE, delegate(void *pvDecoded) { CERT_TEMPLATE_EXT *pTemplateExt = (CERT_TEMPLATE_EXT *)pvDecoded; String actual = Marshal.PtrToStringAnsi(pTemplateExt->pszObjId); String expectedOidValue = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY, expected, OidGroup.Template, fallBackToAllGroups: true).OID; if (expectedOidValue == null) { expectedOidValue = expected; } if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; } })) { return false; } } } GC.KeepAlive(pCertContext); return foundMatch; })); } case X509FindType.FindByApplicationPolicy: { String expected = ConfirmedOidValue(findValue, OidGroup.Policy); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int numOids; int cbData = 0; if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, null, ref cbData)) { return false; } // -1 means the certificate is good for all usages. if (numOids == -1) { return true; } fixed(byte *pOidsPointer = new byte[cbData]) { if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, pOidsPointer, ref cbData)) { return false; } IntPtr *pOids = (IntPtr *)pOidsPointer; for (int i = 0; i < numOids; i++) { String actual = Marshal.PtrToStringAnsi(pOids[i]); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } )); } case X509FindType.FindByCertificatePolicy: { String expected = ConfirmedOidValue(findValue, OidGroup.Policy); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(Oids.CertPolicies, pCertInfo->cExtension, pCertInfo->rgExtension); if (pCertExtension == null) { return false; } bool foundMatch = false; byte[] extensionRawData = pCertExtension->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_CERT_POLICIES, delegate(void *pvDecoded) { CERT_POLICIES_INFO *pCertPoliciesInfo = (CERT_POLICIES_INFO *)pvDecoded; for (int i = 0; i < pCertPoliciesInfo->cPolicyInfo; i++) { CERT_POLICY_INFO *pCertPolicyInfo = &(pCertPoliciesInfo->rgPolicyInfo[i]); String actual = Marshal.PtrToStringAnsi(pCertPolicyInfo->pszPolicyIdentifier); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; break; } } } )) { return false; } GC.KeepAlive(pCertContext); return foundMatch; } )); } case X509FindType.FindByExtension: { String oidValue = ConfirmedOidValue(findValue, OidGroup.ExtensionOrAttribute); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(oidValue, pCertInfo->cExtension, pCertInfo->rgExtension); GC.KeepAlive(pCertContext); return pCertExtension != null; } )); } case X509FindType.FindByKeyUsage: { X509KeyUsageFlags expected = ConfirmedX509KeyUsage(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; X509KeyUsageFlags actual; if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags))) { return true; // no key usage means it is valid for all key usages. } GC.KeepAlive(pCertContext); return (actual & expected) == expected; } )); } case X509FindType.FindBySubjectKeyIdentifier: { byte[] expected = ConfirmedCast <String>(findValue).DecodeHexString(); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int cbData = 0; if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, null, ref cbData)) { return false; } byte[] actual = new byte[cbData]; if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, actual, ref cbData)) { return false; } return expected.ContentsEqual(actual); } )); } default: throw new CryptographicException(SR.Cryptography_X509_InvalidFindType); } } }
public static void FindByValidThumbprint_RootCert() { using (X509Store machineRoot = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { machineRoot.Open(OpenFlags.ReadOnly); using (var watchedStoreCerts = new ImportedCollection(machineRoot.Certificates)) { X509Certificate2Collection storeCerts = watchedStoreCerts.Collection; X509Certificate2 rootCert = null; TimeSpan tolerance = TimeSpan.FromHours(12); // These APIs use local time, so use DateTime.Now, not DateTime.UtcNow. DateTime notBefore = DateTime.Now; DateTime notAfter = DateTime.Now.Subtract(tolerance); foreach (X509Certificate2 cert in storeCerts) { if (cert.NotBefore >= notBefore || cert.NotAfter <= notAfter) { // Not (safely) valid, skip. continue; } X509KeyUsageExtension keyUsageExtension = null; foreach (X509Extension extension in cert.Extensions) { keyUsageExtension = extension as X509KeyUsageExtension; if (keyUsageExtension != null) { break; } } // Some tool is putting the com.apple.systemdefault utility cert in the // LM\Root store on OSX machines; but it gets rejected by OpenSSL as an // invalid root for not having the Certificate Signing key usage value. // // While the real problem seems to be with whatever tool is putting it // in the bundle; we can work around it here. const X509KeyUsageFlags RequiredFlags = X509KeyUsageFlags.KeyCertSign; // No key usage extension means "good for all usages" if (keyUsageExtension != null && (keyUsageExtension.KeyUsages & RequiredFlags) != RequiredFlags) { // Not a valid KeyUsage, skip. continue; } using (ChainHolder chainHolder = new ChainHolder()) { chainHolder.Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; if (!chainHolder.Chain.Build(cert)) { // Despite being not expired and having a valid KeyUsage, it's // not considered a valid root/chain. continue; } } rootCert = cert; break; } // Just in case someone has a system with no valid trusted root certs whatsoever. if (rootCert != null) { X509Certificate2Collection matches = storeCerts.Find(X509FindType.FindByThumbprint, rootCert.Thumbprint, true); using (new ImportedCollection(matches)) { // Improve the debuggability, since the root cert found on each // machine might be different if (matches.Count == 0) { Assert.True( false, $"Root certificate '{rootCert.Subject}' ({rootCert.NotBefore} - {rootCert.NotAfter}) is findable with thumbprint '{rootCert.Thumbprint}' and validOnly=true"); } Assert.NotSame(rootCert, matches[0]); Assert.Equal(rootCert, matches[0]); } } } } }
// CTL == Certificate Trust List / NOT SUPPORTED // TODO - check for X509ChainStatusFlags.CtlNotTimeValid // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage private void PrepareForNextCertificate(int n) { X509ChainElement element = elements [n]; X509Certificate2 certificate = element.Certificate; // TODO 6.1.4.a-b // 6.1.4.c working_issuer_name = certificate.SubjectName; // 6.1.4.d-e - our key includes both the public key and it's parameters working_public_key = certificate.PublicKey.Key; // 6.1.4.f // working_public_key_algorithm = certificate.PublicKey.Oid.Value; // TODO 6.1.4.g-j // 6.1.4.k - Verify that the certificate is a CA certificate X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension); if (bce != null) { if (!bce.CertificateAuthority) { element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints; } } else if (certificate.Version >= 3) { // recent (v3+) CA certificates must include BCE element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints; } // 6.1.4.l - if the certificate isn't self-issued... if (!IsSelfIssued(certificate)) { // ... verify that max_path_length > 0 if (max_path_length > 0) { max_path_length--; } else { // to match MS the reported status must be against the certificate // with the BCE and not where the path is too long. It also means // that this condition has to be reported only once if (bce_restriction != null) { bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints; } } } // 6.1.4.m - if pathLengthConstraint is present... if ((bce != null) && (bce.HasPathLengthConstraint)) { // ... and is less that max_path_length, set max_path_length to it's value if (bce.PathLengthConstraint < max_path_length) { max_path_length = bce.PathLengthConstraint; bce_restriction = element; } } // 6.1.4.n - if key usage extension is present... X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension); if (kue != null) { // ... verify keyCertSign is set X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign; if ((kue.KeyUsages & success) != success) { element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage; } } // 6.1.4.o - recognize and process other critical extension present in the certificate ProcessCertificateExtensions(element); }
private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsage) { foreach (X509Extension extension in c.Extensions) { X509KeyUsageExtension keyUsageExtension = extension as X509KeyUsageExtension; if (keyUsageExtension != null) { if ((keyUsageExtension.KeyUsages & keyUsage) == keyUsage) { return true; } break; } } return false; }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) : base(Oids.KeyUsage, X509Pal.Instance.EncodeX509KeyUsageExtension(keyUsages), critical) { }
public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages) { // The numeric values of X509KeyUsageFlags mean that if we interpret it as a little-endian // ushort it will line up with the flags in the spec. ushort ushortValue = unchecked((ushort)(int)keyUsages); byte[] data = BitConverter.GetBytes(ushortValue); // RFC 3280 section 4.2.1.3 (https://tools.ietf.org/html/rfc3280#section-4.2.1.3) defines // digitalSignature (0) through decipherOnly (8), making 9 named bits. const int namedBitsCount = 9; // The expected output of this method isn't the SEQUENCE value, but just the payload bytes. byte[][] segments = DerEncoder.SegmentedEncodeNamedBitList(data, namedBitsCount); Debug.Assert(segments.Length == 3); return ConcatenateArrays(segments); }
// internal internal X509KeyUsageFlags GetValidFlags (X509KeyUsageFlags flags) { if ((flags & all) != flags) return (X509KeyUsageFlags) 0; return flags; }
public static extern unsafe bool CertGetIntendedKeyUsage(CertEncodingType dwCertEncodingType, CERT_INFO *pCertInfo, out X509KeyUsageFlags pbKeyUsage, int cbKeyUsage);
internal AsnDecodeStatus Decode (byte[] extension) { if ((extension == null) || (extension.Length == 0)) return AsnDecodeStatus.BadAsn; if (extension [0] != 0x03) return AsnDecodeStatus.BadTag; if (extension.Length < 3) return AsnDecodeStatus.BadLength; if (extension.Length < 4) return AsnDecodeStatus.InformationNotAvailable; try { ASN1 ex = new ASN1 (extension); int kubits = 0; int i = 1; // byte zero has the number of unused bits (ASN1's BITSTRING) while (i < ex.Value.Length) kubits = (kubits << 8) + ex.Value [i++]; _keyUsages = GetValidFlags ((X509KeyUsageFlags)kubits); } catch { return AsnDecodeStatus.BadAsn; } return AsnDecodeStatus.Ok; }
private static unsafe byte[] EncodeExtension (X509KeyUsageFlags keyUsages) { CAPI.CRYPT_BIT_BLOB blob = new CAPI.CRYPT_BIT_BLOB(); blob.cbData = 2; blob.pbData = new IntPtr(&keyUsages); blob.cUnusedBits = 0; byte[] encodedKeyUsages = null; if (!CAPI.EncodeObject(CAPI.szOID_KEY_USAGE, new IntPtr(&blob), out encodedKeyUsages)) throw new CryptographicException(Marshal.GetLastWin32Error()); return encodedKeyUsages; }
private static X509Certificate2 AskCertificate(X509KeyUsageFlags flags) { X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser); my.Open(OpenFlags.ReadOnly); try { X509Certificate2Collection nonRep = my.Certificates.Find(X509FindType.FindByKeyUsage, flags, true); return X509Certificate2UI.SelectFromCollection(nonRep, "Select your cert", "Select the cert you want to used to sign the msg", X509SelectionFlag.SingleSelection)[0]; } finally { my.Close(); } }
public unsafe void FindByKeyUsage(X509KeyUsageFlags keyUsage) { FindCore( delegate (SafeCertContextHandle pCertContext) { CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo; X509KeyUsageFlags actual; if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags))) return true; // no key usage means it is valid for all key usages. GC.KeepAlive(pCertContext); return (actual & keyUsage) == keyUsage; }); }
private X509KeyUsageExtension ValidateKeyUsage (X509KeyUsageFlags kuf, string rawdata) { X509KeyUsageExtension ku = new X509KeyUsageExtension (kuf, false); Assert.IsFalse (ku.Critical, kuf.ToString () + ".Critical"); Assert.AreEqual (rawdata, BitConverter.ToString (ku.RawData), kuf.ToString () + ".RawData"); Assert.AreEqual (oid, ku.Oid.Value, kuf.ToString () + ".Oid.Value"); Assert.AreEqual (fname, ku.Oid.FriendlyName, kuf.ToString () + ".Oid.FriendlyName"); Assert.AreEqual (kuf, ku.KeyUsages, kuf.ToString () + ".KeyUsages"); return ku; }
public void FindByKeyUsage(X509KeyUsageFlags keyUsage) { FindCore( cert => { X509Extension ext = FindExtension(cert, Oids.KeyUsage); if (ext == null) { // A certificate with no key usage extension is considered valid for all key usages. return true; } var kuExt = (X509KeyUsageExtension)ext; return (kuExt.KeyUsages & keyUsage) == keyUsage; }); }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) : base("2.5.29.15", EncodeExtension(keyUsages), critical) { }
private static void TestKeyUsageExtension(X509KeyUsageFlags flags, bool critical, byte[] expectedDer) { X509KeyUsageExtension ext = new X509KeyUsageExtension(flags, critical); byte[] rawData = ext.RawData; Assert.Equal(expectedDer, rawData); // Assert that format doesn't crash string s = ext.Format(false); // Rebuild it from the RawData. ext = new X509KeyUsageExtension(new AsnEncodedData(rawData), critical); Assert.Equal(flags, ext.KeyUsages); }
private X509KeyUsageExtension ValidateKeyUsage (X509KeyUsageFlags kuf, string rawdata) { X509KeyUsageExtension ku = new X509KeyUsageExtension (kuf, false); Assert.IsFalse (ku.Critical, kuf.ToString () + ".Critical"); Assert.AreEqual (rawdata, BitConverter.ToString (ku.RawData), kuf.ToString () + ".RawData"); Assert.AreEqual (oid, ku.Oid.Value, kuf.ToString () + ".Oid.Value"); // FIXME: Don't expect that FriendlyName is English. This test fails under non-English Windows. //Assert.AreEqual (fname, ku.Oid.FriendlyName, kuf.ToString () + ".Oid.FriendlyName"); Assert.AreEqual (kuf, ku.KeyUsages, kuf.ToString () + ".KeyUsages"); return ku; }
public static X509Certificate2Collection FindFromCollection( X509Certificate2Collection coll, X509FindType findType, object findValue, bool validOnly) { X509Certificate2Collection results = new X509Certificate2Collection(); using (IFindPal findPal = OpenPal(coll, results, validOnly)) { switch (findType) { case X509FindType.FindByThumbprint: { byte[] thumbPrint = ConfirmedCast <string>(findValue).LaxDecodeHexString(); findPal.FindByThumbprint(thumbPrint); break; } case X509FindType.FindBySubjectName: { string subjectName = ConfirmedCast <string>(findValue); findPal.FindBySubjectName(subjectName); break; } case X509FindType.FindBySubjectDistinguishedName: { string subjectDistinguishedName = ConfirmedCast <string>(findValue); findPal.FindBySubjectDistinguishedName(subjectDistinguishedName); break; } case X509FindType.FindByIssuerName: { string issuerName = ConfirmedCast <string>(findValue); findPal.FindByIssuerName(issuerName); break; } case X509FindType.FindByIssuerDistinguishedName: { string issuerDistinguishedName = ConfirmedCast <string>(findValue); findPal.FindByIssuerDistinguishedName(issuerDistinguishedName); break; } case X509FindType.FindBySerialNumber: { string decimalOrHexString = ConfirmedCast <string>(findValue); // FindBySerialNumber allows the input format to be either in // hex or decimal. Since we can't know which one was intended, // it compares against both interpretations and treats a match // of either as a successful find. // string is big-endian byte[] hexBytes = decimalOrHexString.LaxDecodeHexString(); BigInteger hexValue = new BigInteger(hexBytes, isUnsigned: true, isBigEndian: true); BigInteger decimalValue = LaxParseDecimalBigInteger(decimalOrHexString); findPal.FindBySerialNumber(hexValue, decimalValue); break; } case X509FindType.FindByTimeValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); findPal.FindByTimeValid(dateTime); break; } case X509FindType.FindByTimeNotYetValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); findPal.FindByTimeNotYetValid(dateTime); break; } case X509FindType.FindByTimeExpired: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); findPal.FindByTimeExpired(dateTime); break; } case X509FindType.FindByTemplateName: { string expected = ConfirmedCast <string>(findValue); findPal.FindByTemplateName(expected); break; } case X509FindType.FindByApplicationPolicy: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy); findPal.FindByApplicationPolicy(oidValue); break; } case X509FindType.FindByCertificatePolicy: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy); findPal.FindByCertificatePolicy(oidValue); break; } case X509FindType.FindByExtension: { string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.ExtensionOrAttribute); findPal.FindByExtension(oidValue); break; } case X509FindType.FindByKeyUsage: { X509KeyUsageFlags keyUsage = ConfirmedX509KeyUsage(findValue); findPal.FindByKeyUsage(keyUsage); break; } case X509FindType.FindBySubjectKeyIdentifier: { byte[] keyIdentifier = ConfirmedCast <string>(findValue).LaxDecodeHexString(); findPal.FindBySubjectKeyIdentifier(keyIdentifier); break; } default: throw new CryptographicException(SR.Cryptography_X509_InvalidFindType); } } return(results); }
public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages) { throw new NotImplementedException(); }
private X509ChainStatusFlags CheckRevocation(X509Certificate2 certificate, X509Certificate2 ca_cert, bool online) { // change this if/when we support OCSP X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension); if (kue != null) { // ... verify CrlSign is set X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign; if ((kue.KeyUsages & success) != success) { // FIXME - we should try to find an alternative CA that has the CrlSign bit return(X509ChainStatusFlags.RevocationStatusUnknown); } } MX.X509Crl crl = FindCrl(ca_cert); if ((crl == null) && online) { // FIXME - download and install new CRL // then you get a second chance // crl = FindCrl (ca_cert, ref valid, ref out_of_date); // We need to get the subjectAltName and an URI from there (or use OCSP) // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension); } if (crl != null) { // validate the digital signature on the CRL using the CA public key // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates // checks and we loose the "why" of the failure // note #2: we do this before other tests as an invalid signature could be a hacked CRL // (so anything within can't be trusted) if (!crl.VerifySignature(ca_cert.PublicKey.Key)) { return(X509ChainStatusFlags.RevocationStatusUnknown); } MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry(certificate.MonoCertificate); if (entry != null) { // We have an entry for this CRL that includes an unknown CRITICAL extension // See [X.509 7.3] NOTE 4 if (!ProcessCrlEntryExtensions(entry)) { return(X509ChainStatusFlags.Revoked); } // FIXME - a little more is involved if (entry.RevocationDate <= ChainPolicy.VerificationTime) { return(X509ChainStatusFlags.Revoked); } } // are we overdue for a CRL update ? if so we can't be sure of any certificate status if (crl.NextUpdate < ChainPolicy.VerificationTime) { return(X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation); } // we have a CRL that includes an unknown CRITICAL extension // we put this check at the end so we do not "hide" any Revoked flags if (!ProcessCrlExtensions(crl)) { return(X509ChainStatusFlags.RevocationStatusUnknown); } } else { return(X509ChainStatusFlags.RevocationStatusUnknown); } return(X509ChainStatusFlags.NoError); }
/// <summary> /// Throws an exception if validation fails. /// </summary> /// <param name="certificates">The certificates to be checked.</param> /// <exception cref="ServiceResultException">If certificate[0] cannot be accepted</exception> protected virtual async Task InternalValidate(X509Certificate2Collection certificates) { X509Certificate2 certificate = certificates[0]; // check for previously validated certificate. X509Certificate2 certificate2 = null; if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2)) { if (Utils.IsEqual(certificate2.RawData, certificate.RawData)) { return; } } CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate); // get the issuers (checks the revocation lists if using directory stores). List <CertificateIdentifier> issuers = new List <CertificateIdentifier>(); bool isIssuerTrusted = await GetIssuers(certificates, issuers); // setup policy chain X509ChainPolicy policy = new X509ChainPolicy(); policy.RevocationFlag = X509RevocationFlag.EntireChain; policy.RevocationMode = X509RevocationMode.NoCheck; policy.VerificationFlags = X509VerificationFlags.NoFlag; foreach (CertificateIdentifier issuer in issuers) { if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0) { policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown; policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown; } // we did the revocation check in the GetIssuers call. No need here. policy.RevocationMode = X509RevocationMode.NoCheck; policy.ExtraStore.Add(issuer.Certificate); } // build chain. bool chainStatusChecked = false; X509Chain chain = new X509Chain(); chain.ChainPolicy = policy; chain.Build(certificate); // check the chain results. CertificateIdentifier target = trustedCertificate; if (target == null) { target = new CertificateIdentifier(certificate); } for (int ii = 0; ii < chain.ChainElements.Count; ii++) { X509ChainElement element = chain.ChainElements[ii]; CertificateIdentifier issuer = null; if (ii < issuers.Count) { issuer = issuers[ii]; } // check for chain status errors. foreach (X509ChainStatus status in element.ChainElementStatus) { ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0)); if (ServiceResult.IsBad(result)) { // check untrusted certificates. if (trustedCertificate == null) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed); } throw new ServiceResultException(result); } chainStatusChecked = true; } if (issuer != null) { target = issuer; } } // check whether the chain is complete (if there is a chain) bool issuedByCA = !Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer); bool chainIncomplete = false; if (issuers.Count > 0) { var rootCertificate = issuers[issuers.Count - 1].Certificate; if (!Utils.CompareDistinguishedName(rootCertificate.Subject, rootCertificate.Issuer)) { chainIncomplete = true; } } else { if (issuedByCA) { // no issuer found at all chainIncomplete = true; } } if (issuedByCA && (!chainStatusChecked || chainIncomplete)) { throw ServiceResultException.Create( StatusCodes.BadCertificateChainIncomplete, "Certificate chain validation incomplete.\r\nSubjectName: {0}\r\nIssuerName: {1}", certificate.SubjectName.Name, certificate.IssuerName.Name); } // check if certificate issuer is trusted. if (issuedByCA && !isIssuerTrusted && trustedCertificate == null) { if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData)) { throw ServiceResultException.Create( StatusCodes.BadCertificateUntrusted, "Certificate issuer is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}", certificate.SubjectName.Name, certificate.IssuerName.Name); } } // check if certificate is trusted. if (trustedCertificate == null && !isIssuerTrusted) { if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData)) { throw ServiceResultException.Create( StatusCodes.BadCertificateUntrusted, "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}", certificate.SubjectName.Name, certificate.IssuerName.Name); } } // check if certificate is valid for use as app/sw or user cert X509KeyUsageFlags certificateKeyUsage = CertificateFactory.GetKeyUsage(certificate); if ((certificateKeyUsage & X509KeyUsageFlags.DataEncipherment) == 0) { throw new ServiceResultException(StatusCodes.BadCertificateUseNotAllowed, "Usage of certificate is not allowed."); } // check if minimum requirements are met if (m_rejectSHA1SignedCertificates && IsSHA1SignatureAlgorithm(certificate.SignatureAlgorithm)) { throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "SHA1 signed certificates are not trusted"); } if (certificate.GetRSAPublicKey().KeySize < m_minimumCertificateKeySize) { throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "Certificate doesn't meet minimum key length requirement"); } }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) { }
public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) : base(CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) { }
internal static unsafe partial bool CertGetIntendedKeyUsage( CertEncodingType dwCertEncodingType, CERT_INFO *pCertInfo, out X509KeyUsageFlags pbKeyUsage, int cbKeyUsage);
/// <summary> /// Finds a certificate in the user's local store based on its subject and usage flags /// </summary> /// <param name="subjectDistinguishedName">The subject distinguished name of the certificate</param> /// <param name="usage">The minimum usage flags the certificate must contain</param> /// <returns>The requested certificate, or null if the certificate is not found</returns> public static X509Certificate2 FindCertificate(string subjectDistinguishedName, X509KeyUsageFlags usage) { X509Store localStore = new X509Store(StoreName.My); localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); try { X509Certificate2Collection matches = localStore.Certificates.Find( X509FindType.FindBySubjectDistinguishedName, subjectDistinguishedName, true); if (matches.Count > 0) { foreach (X509Certificate2 cert in matches) { foreach (X509Extension extension in cert.Extensions) { X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension; if (usageExtension != null) { bool matchesUsageRequirements = ((usage & usageExtension.KeyUsages) == usage); if (matchesUsageRequirements) { return(cert); } } } } return(null); } else { return(null); } } finally { localStore.Close(); } }