csharp.lang.security.cryptography.x509-subject-name-validation.X509-subject-name-validation

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Validating certificates based on subject name is bad practice. Use the X509Certificate2.Verify() method instead.

Run Locally

Run in CI

Defintion

rules:
  - id: X509-subject-name-validation
    severity: WARNING
    languages:
      - csharp
    metadata:
      cwe:
        - "CWE-295: Improper Certificate Validation"
      owasp:
        - A03:2017 - Sensitive Data Exposure
        - A07:2021 - Identification and Authentication Failures
      references:
        - https://docs.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.issuernameregistry?view=netframework-4.8
      category: security
      technology:
        - .net
      confidence: MEDIUM
      subcategory:
        - vuln
      likelihood: LOW
      impact: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Improper Authentication
    message: Validating certificates based on subject name is bad practice. Use the
      X509Certificate2.Verify() method instead.
    patterns:
      - pattern-inside: |
          using System.IdentityModel.Tokens;
          ...
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      X509SecurityToken $TOK = $RHS;
                      ...
                  - pattern-inside: |
                      $T $M(..., X509SecurityToken $TOK, ...) {
                          ...
                      }
              - metavariable-pattern:
                  metavariable: $RHS
                  pattern-either:
                    - pattern: $T as X509SecurityToken
                    - pattern: new X509SecurityToken(...)
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      X509Certificate2 $CERT = new X509Certificate2(...);
                      ...
                  - pattern-inside: |
                      $T $M(..., X509Certificate2 $CERT, ...) {
                          ...
                      }
                  - pattern-inside: |
                      foreach (X509Certificate2 $CERT in $COLLECTION) {
                          ...
                      }
      - patterns:
          - pattern-either:
              - pattern: String.Equals($NAME, "...")
              - pattern: String.Equals("...", $NAME)
              - pattern: $NAME.Equals("...")
              - pattern: $NAME == "..."
              - pattern: $NAME != "..."
              - pattern: |
                  "..." == $NAME
              - pattern: |
                  "..." != $NAME
          - metavariable-pattern:
              metavariable: $NAME
              pattern-either:
                - pattern: $TOK.Certificate.SubjectName.Name
                - pattern: $CERT.SubjectName.Name
                - pattern: $CERT.GetNameInfo(...)

Examples

X509-subject-name-validation.cs

using System.IdentityModel.Tokens;

namespace System.IdentityModel.Samples
{
    public class TrustedIssuerNameRegistry : IssuerNameRegistry
    {
        public override string GetIssuerName(SecurityToken securityToken)
        {
            X509SecurityToken x509Token = securityToken as X509SecurityToken;
            if (x509Token != null)
            {
                // ruleid: X509-subject-name-validation
                if (String.Equals(x509Token.Certificate.SubjectName.Name, "CN=localhost"))
                {
                    return x509Token.Certificate.SubjectName.Name;
                }

                // ruleid: X509-subject-name-validation
                if (String.Equals("CN=localhost", x509Token.Certificate.SubjectName.Name))
                {
                    return x509Token.Certificate.SubjectName.Name;
                }
            }

            // ok
            if(String.Equals("Hello", "Goodbye")) { }
        }

        public override string GetIssuerName2() // no args
        {
            X509SecurityToken x509Token = new X509SecurityToken();
            if (x509Token != null)
            {
                // ruleid: X509-subject-name-validation
                if (x509Token.Certificate.SubjectName.Name.Equals("CN=localhost"))
                {
                    return x509Token.Certificate.SubjectName.Name;
                }
            }
        }

        public override string GetIssuerName3()
        {
            X509SecurityToken x509Token = new X509SecurityToken();
            if (x509Token != null)
            {
                // ruleid: X509-subject-name-validation
                if ("CN=localhost" == x509Token.Certificate.SubjectName.Name)
                {
                    return x509Token.Certificate.SubjectName.Name;
                }

                // ruleid: X509-subject-name-validation
                if (x509Token.Certificate.SubjectName.Name == "CN=localhost")
                {
                    return x509Token.Certificate.SubjectName.Name;
                }
            }
        }

        public override string GetIssuerNameLoop()
        {
            X509Store store = new X509Store("MY",StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
            X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid,DateTime.Now,false);
            X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select","Select a certificate from the following list to get information on that certificate",X509SelectionFlag.MultiSelection);

            foreach (X509Certificate2 x509 in scollection)
            {
                // ruleid: X509-subject-name-validation
                String.Equals(x509.GetNameInfo(X509NameType.SimpleName), "CN=localhost");

                // ruleid: X509-subject-name-validation
                if(x509.SubjectName.Name == "CN=localhost") { }
            }
            store.Close();
        }
    }
}