...

Source file src/crypto/x509/parser_test.go

Documentation: crypto/x509

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x509
     6  
     7  import (
     8  	"encoding/asn1"
     9  	"encoding/pem"
    10  	"os"
    11  	"strings"
    12  	"testing"
    13  
    14  	cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
    15  )
    16  
    17  func TestParseASN1String(t *testing.T) {
    18  	tests := []struct {
    19  		name        string
    20  		tag         cryptobyte_asn1.Tag
    21  		value       []byte
    22  		expected    string
    23  		expectedErr string
    24  	}{
    25  		{
    26  			name:     "T61String",
    27  			tag:      cryptobyte_asn1.T61String,
    28  			value:    []byte{80, 81, 82},
    29  			expected: string("PQR"),
    30  		},
    31  		{
    32  			name:     "PrintableString",
    33  			tag:      cryptobyte_asn1.PrintableString,
    34  			value:    []byte{80, 81, 82},
    35  			expected: string("PQR"),
    36  		},
    37  		{
    38  			name:        "PrintableString (invalid)",
    39  			tag:         cryptobyte_asn1.PrintableString,
    40  			value:       []byte{1, 2, 3},
    41  			expectedErr: "invalid PrintableString",
    42  		},
    43  		{
    44  			name:     "UTF8String",
    45  			tag:      cryptobyte_asn1.UTF8String,
    46  			value:    []byte{80, 81, 82},
    47  			expected: string("PQR"),
    48  		},
    49  		{
    50  			name:        "UTF8String (invalid)",
    51  			tag:         cryptobyte_asn1.UTF8String,
    52  			value:       []byte{255},
    53  			expectedErr: "invalid UTF-8 string",
    54  		},
    55  		{
    56  			name:     "BMPString",
    57  			tag:      cryptobyte_asn1.Tag(asn1.TagBMPString),
    58  			value:    []byte{80, 81},
    59  			expected: string("偑"),
    60  		},
    61  		{
    62  			name:        "BMPString (invalid length)",
    63  			tag:         cryptobyte_asn1.Tag(asn1.TagBMPString),
    64  			value:       []byte{255},
    65  			expectedErr: "invalid BMPString",
    66  		},
    67  		{
    68  			name:     "IA5String",
    69  			tag:      cryptobyte_asn1.IA5String,
    70  			value:    []byte{80, 81},
    71  			expected: string("PQ"),
    72  		},
    73  		{
    74  			name:        "IA5String (invalid)",
    75  			tag:         cryptobyte_asn1.IA5String,
    76  			value:       []byte{255},
    77  			expectedErr: "invalid IA5String",
    78  		},
    79  		{
    80  			name:     "NumericString",
    81  			tag:      cryptobyte_asn1.Tag(asn1.TagNumericString),
    82  			value:    []byte{49, 50},
    83  			expected: string("12"),
    84  		},
    85  		{
    86  			name:        "NumericString (invalid)",
    87  			tag:         cryptobyte_asn1.Tag(asn1.TagNumericString),
    88  			value:       []byte{80},
    89  			expectedErr: "invalid NumericString",
    90  		},
    91  	}
    92  
    93  	for _, tc := range tests {
    94  		t.Run(tc.name, func(t *testing.T) {
    95  			out, err := parseASN1String(tc.tag, tc.value)
    96  			if err != nil && err.Error() != tc.expectedErr {
    97  				t.Fatalf("parseASN1String returned unexpected error: got %q, want %q", err, tc.expectedErr)
    98  			} else if err == nil && tc.expectedErr != "" {
    99  				t.Fatalf("parseASN1String didn't fail, expected: %s", tc.expectedErr)
   100  			}
   101  			if out != tc.expected {
   102  				t.Fatalf("parseASN1String returned unexpected value: got %q, want %q", out, tc.expected)
   103  			}
   104  		})
   105  	}
   106  }
   107  
   108  const policyPEM = `-----BEGIN CERTIFICATE-----
   109  MIIGeDCCBWCgAwIBAgIUED9KQBi0ScBDoufB2mgAJ63G5uIwDQYJKoZIhvcNAQEL
   110  BQAwVTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsG
   111  A1UECxMERlBLSTEdMBsGA1UEAxMURmVkZXJhbCBCcmlkZ2UgQ0EgRzQwHhcNMjAx
   112  MDIyMTcwNDE5WhcNMjMxMDIyMTcwNDE5WjCBgTELMAkGA1UEBhMCVVMxHTAbBgNV
   113  BAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVz
   114  dCBOZXR3b3JrMTIwMAYDVQQDEylTeW1hbnRlYyBDbGFzcyAzIFNTUCBJbnRlcm1l
   115  ZGlhdGUgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2p
   116  75cMpx86sS2aH4r+0o8r+m/KTrPrknWP0RA9Kp6sewAzkNa7BVwg0jOhyamiv1iP
   117  Cns10usoH93nxYbXLWF54vOLRdYU/53KEPNmgkj2ipMaTLuaReBghNibikWSnAmy
   118  S8RItaDMs8tdF2goKPI4xWiamNwqe92VC+pic2tq0Nva3Y4kvMDJjtyje3uduTtL
   119  oyoaaHkrX7i7gE67psnMKj1THUtre1JV1ohl9+oOuyot4p3eSxVlrMWiiwb11bnk
   120  CakecOz/mP2DHMGg6pZ/BeJ+ThaLUylAXECARIqHc9UwRPKC9BfLaCX4edIoeYiB
   121  loRs4KdqLdg/I9eTwKkCAwEAAaOCAxEwggMNMB0GA1UdDgQWBBQ1Jn1QleGhwb0F
   122  1cOdd0LHDBOWjDAfBgNVHSMEGDAWgBR58ABJ6393wl1BAmU0ipAjmx4HbzAOBgNV
   123  HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCBiAYDVR0gBIGAMH4wDAYKYIZI
   124  AWUDAgEDAzAMBgpghkgBZQMCAQMMMAwGCmCGSAFlAwIBAw4wDAYKYIZIAWUDAgED
   125  DzAMBgpghkgBZQMCAQMSMAwGCmCGSAFlAwIBAxMwDAYKYIZIAWUDAgEDFDAMBgpg
   126  hkgBZQMCAQMlMAwGCmCGSAFlAwIBAyYwggESBgNVHSEEggEJMIIBBTAbBgpghkgB
   127  ZQMCAQMDBg1ghkgBhvhFAQcXAwEGMBsGCmCGSAFlAwIBAwwGDWCGSAGG+EUBBxcD
   128  AQcwGwYKYIZIAWUDAgEDDgYNYIZIAYb4RQEHFwMBDjAbBgpghkgBZQMCAQMPBg1g
   129  hkgBhvhFAQcXAwEPMBsGCmCGSAFlAwIBAxIGDWCGSAGG+EUBBxcDARIwGwYKYIZI
   130  AWUDAgEDEwYNYIZIAYb4RQEHFwMBETAbBgpghkgBZQMCAQMUBg1ghkgBhvhFAQcX
   131  AwEUMBsGCmCGSAFlAwIBAyUGDWCGSAGG+EUBBxcDAQgwGwYKYIZIAWUDAgEDJgYN
   132  YIZIAYb4RQEHFwMBJDBgBggrBgEFBQcBCwRUMFIwUAYIKwYBBQUHMAWGRGh0dHA6
   133  Ly9zc3Atc2lhLnN5bWF1dGguY29tL1NUTlNTUC9DZXJ0c19Jc3N1ZWRfYnlfQ2xh
   134  c3MzU1NQQ0EtRzMucDdjMA8GA1UdJAQIMAaAAQCBAQAwCgYDVR02BAMCAQAwUQYI
   135  KwYBBQUHAQEERTBDMEEGCCsGAQUFBzAChjVodHRwOi8vcmVwby5mcGtpLmdvdi9i
   136  cmlkZ2UvY2FDZXJ0c0lzc3VlZFRvZmJjYWc0LnA3YzA3BgNVHR8EMDAuMCygKqAo
   137  hiZodHRwOi8vcmVwby5mcGtpLmdvdi9icmlkZ2UvZmJjYWc0LmNybDANBgkqhkiG
   138  9w0BAQsFAAOCAQEAA751TycC1f/WTkHmedF9ZWxP58Jstmwvkyo8bKueJ0eF7LTG
   139  BgQlzE2B9vke4sFhd4V+BdgOPGE1dsGzllYKCWg0BhkCBs5kIJ7F6Ay6G1TBuGU1
   140  Ie8247GL+P9pcC5TVvXHC/62R2w3DuD/vAPLbYEbSQjobXlsqt8Kmtd6yK/jVuDV
   141  BTZMdZmvoNtjemqmgcBXHsf0ctVm0m6tH5uYqyVxu8tfyUis6Cf303PHj+spWP1k
   142  gc5PYnVF0ot7qAmNFENIpbKg3BdusBkF9rGxLaDSUBvSc7+s9iQz9d/iRuAebrYu
   143  +eqUlJ2lsjS1U8qyPmlH+spfPNbAEQEsuP32Aw==
   144  -----END CERTIFICATE-----
   145  `
   146  
   147  func TestPolicyParse(t *testing.T) {
   148  	b, _ := pem.Decode([]byte(policyPEM))
   149  	c, err := ParseCertificate(b.Bytes)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	if len(c.Policies) != 9 {
   154  		t.Errorf("unexpected number of policies: got %d, want %d", len(c.Policies), 9)
   155  	}
   156  	if len(c.PolicyMappings) != 9 {
   157  		t.Errorf("unexpected number of policy mappings: got %d, want %d", len(c.PolicyMappings), 9)
   158  	}
   159  	if !c.RequireExplicitPolicyZero {
   160  		t.Error("expected RequireExplicitPolicyZero to be set")
   161  	}
   162  	if !c.InhibitPolicyMappingZero {
   163  		t.Error("expected InhibitPolicyMappingZero to be set")
   164  	}
   165  	if !c.InhibitAnyPolicyZero {
   166  		t.Error("expected InhibitAnyPolicyZero to be set")
   167  	}
   168  }
   169  
   170  func TestParsePolicies(t *testing.T) {
   171  	for _, tc := range []string{
   172  		"testdata/policy_leaf_duplicate.pem",
   173  		"testdata/policy_leaf_invalid.pem",
   174  	} {
   175  		t.Run(tc, func(t *testing.T) {
   176  			b, err := os.ReadFile(tc)
   177  			if err != nil {
   178  				t.Fatal(err)
   179  			}
   180  			p, _ := pem.Decode(b)
   181  			_, err = ParseCertificate(p.Bytes)
   182  			if err == nil {
   183  				t.Error("parsing should've failed")
   184  			}
   185  		})
   186  	}
   187  }
   188  
   189  func TestDomainNameValid(t *testing.T) {
   190  	for _, tc := range []struct {
   191  		name       string
   192  		dnsName    string
   193  		constraint bool
   194  		valid      bool
   195  	}{
   196  		{"empty name, name", "", false, false},
   197  		{"empty name, constraint", "", true, true},
   198  		{"empty label, name", "a..a", false, false},
   199  		{"empty label, constraint", "a..a", true, false},
   200  		{"period, name", ".", false, false},
   201  		{"period, constraint", ".", true, false}, // TODO(roland): not entirely clear if this is a valid constraint (require at least one label?)
   202  		{"valid, name", "a.b.c", false, true},
   203  		{"valid, constraint", "a.b.c", true, true},
   204  		{"leading period, name", ".a.b.c", false, false},
   205  		{"leading period, constraint", ".a.b.c", true, true},
   206  		{"trailing period, name", "a.", false, false},
   207  		{"trailing period, constraint", "a.", true, false},
   208  		{"bare label, name", "a", false, true},
   209  		{"bare label, constraint", "a", true, true},
   210  		{"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false},
   211  		{"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false},
   212  		{"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false},
   213  		{"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false},
   214  		{"64 char single label, name", strings.Repeat("a", 64), false, false},
   215  		{"64 char single label, constraint", strings.Repeat("a", 64), true, false},
   216  		{"63 char single label, name", strings.Repeat("a", 63), false, true},
   217  		{"63 char single label, constraint", strings.Repeat("a", 63), true, true},
   218  		{"64 char label, name", "a." + strings.Repeat("a", 64), false, false},
   219  		{"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false},
   220  		{"63 char label, name", "a." + strings.Repeat("a", 63), false, true},
   221  		{"63 char label, constraint", "a." + strings.Repeat("a", 63), true, true},
   222  	} {
   223  		t.Run(tc.name, func(t *testing.T) {
   224  			if tc.valid != domainNameValid(tc.dnsName, tc.constraint) {
   225  				t.Errorf("domainNameValid(%q, %t) = %v; want %v", tc.dnsName, tc.constraint, !tc.valid, tc.valid)
   226  			}
   227  		})
   228  	}
   229  }
   230  

View as plain text