github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/crypto/x509/platform_test.go (about) 1 // Copyright 2023 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 "crypto/ecdsa" 9 "crypto/elliptic" 10 "crypto/rand" 11 "encoding/pem" 12 "math/big" 13 "os" 14 "runtime" 15 "strings" 16 "testing" 17 "time" 18 ) 19 20 // In order to run this test suite locally, you need to insert the test root, at 21 // the path below, into your trust store. This root is constrained such that it 22 // should not be dangerous to local developers to trust, but care should be 23 // taken when inserting it into the trust store not to give it increased 24 // permissions. 25 // 26 // On macOS the certificate can be further constrained to only be valid for 27 // 'SSL' in the certificate properties pane of the 'Keychain Access' program. 28 // 29 // On Windows the certificate can also be constrained to only server 30 // authentication in the properties pane of the certificate in the 31 // "Certificates" snap-in of mmc.exe. 32 33 const ( 34 rootCertPath = "platform_root_cert.pem" 35 rootKeyPath = "platform_root_key.pem" 36 ) 37 38 func TestPlatformVerifier(t *testing.T) { 39 if runtime.GOOS != "windows" && runtime.GOOS != "darwin" { 40 t.Skip("only tested on windows and darwin") 41 } 42 43 der, err := os.ReadFile(rootCertPath) 44 if err != nil { 45 t.Fatalf("failed to read test root: %s", err) 46 } 47 b, _ := pem.Decode(der) 48 testRoot, err := ParseCertificate(b.Bytes) 49 if err != nil { 50 t.Fatalf("failed to parse test root: %s", err) 51 } 52 53 der, err = os.ReadFile(rootKeyPath) 54 if err != nil { 55 t.Fatalf("failed to read test key: %s", err) 56 } 57 b, _ = pem.Decode(der) 58 testRootKey, err := ParseECPrivateKey(b.Bytes) 59 if err != nil { 60 t.Fatalf("failed to parse test key: %s", err) 61 } 62 63 if _, err := testRoot.Verify(VerifyOptions{}); err != nil { 64 t.Skipf("test root is not in trust store, skipping (err: %q)", err) 65 } 66 67 now := time.Now() 68 69 tests := []struct { 70 name string 71 cert *Certificate 72 selfSigned bool 73 dnsName string 74 time time.Time 75 eku []ExtKeyUsage 76 77 expectedErr string 78 windowsErr string 79 macosErr string 80 }{ 81 { 82 name: "valid", 83 cert: &Certificate{ 84 SerialNumber: big.NewInt(1), 85 DNSNames: []string{"valid.testing.golang.invalid"}, 86 NotBefore: now.Add(-time.Hour), 87 NotAfter: now.Add(time.Hour), 88 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 89 }, 90 }, 91 { 92 name: "valid (with name)", 93 cert: &Certificate{ 94 SerialNumber: big.NewInt(1), 95 DNSNames: []string{"valid.testing.golang.invalid"}, 96 NotBefore: now.Add(-time.Hour), 97 NotAfter: now.Add(time.Hour), 98 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 99 }, 100 dnsName: "valid.testing.golang.invalid", 101 }, 102 { 103 name: "valid (with time)", 104 cert: &Certificate{ 105 SerialNumber: big.NewInt(1), 106 DNSNames: []string{"valid.testing.golang.invalid"}, 107 NotBefore: now.Add(-time.Hour), 108 NotAfter: now.Add(time.Hour), 109 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 110 }, 111 time: now.Add(time.Minute * 30), 112 }, 113 { 114 name: "valid (with eku)", 115 cert: &Certificate{ 116 SerialNumber: big.NewInt(1), 117 DNSNames: []string{"valid.testing.golang.invalid"}, 118 NotBefore: now.Add(-time.Hour), 119 NotAfter: now.Add(time.Hour), 120 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 121 }, 122 eku: []ExtKeyUsage{ExtKeyUsageServerAuth}, 123 }, 124 { 125 name: "wrong name", 126 cert: &Certificate{ 127 SerialNumber: big.NewInt(1), 128 DNSNames: []string{"valid.testing.golang.invalid"}, 129 NotBefore: now.Add(-time.Hour), 130 NotAfter: now.Add(time.Hour), 131 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 132 }, 133 dnsName: "invalid.testing.golang.invalid", 134 expectedErr: "x509: certificate is valid for valid.testing.golang.invalid, not invalid.testing.golang.invalid", 135 }, 136 { 137 name: "expired (future)", 138 cert: &Certificate{ 139 SerialNumber: big.NewInt(1), 140 DNSNames: []string{"valid.testing.golang.invalid"}, 141 NotBefore: now.Add(-time.Hour), 142 NotAfter: now.Add(time.Hour), 143 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 144 }, 145 time: now.Add(time.Hour * 2), 146 expectedErr: "x509: certificate has expired or is not yet valid", 147 }, 148 { 149 name: "expired (past)", 150 cert: &Certificate{ 151 SerialNumber: big.NewInt(1), 152 DNSNames: []string{"valid.testing.golang.invalid"}, 153 NotBefore: now.Add(-time.Hour), 154 NotAfter: now.Add(time.Hour), 155 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 156 }, 157 time: now.Add(time.Hour * 2), 158 expectedErr: "x509: certificate has expired or is not yet valid", 159 }, 160 { 161 name: "self-signed", 162 cert: &Certificate{ 163 SerialNumber: big.NewInt(1), 164 DNSNames: []string{"valid.testing.golang.invalid"}, 165 NotBefore: now.Add(-time.Hour), 166 NotAfter: now.Add(time.Hour), 167 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 168 }, 169 selfSigned: true, 170 macosErr: "x509: “valid.testing.golang.invalid” certificate is not trusted", 171 windowsErr: "x509: certificate signed by unknown authority", 172 }, 173 { 174 name: "non-specified KU", 175 cert: &Certificate{ 176 SerialNumber: big.NewInt(1), 177 DNSNames: []string{"valid.testing.golang.invalid"}, 178 NotBefore: now.Add(-time.Hour), 179 NotAfter: now.Add(time.Hour), 180 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, 181 }, 182 eku: []ExtKeyUsage{ExtKeyUsageEmailProtection}, 183 expectedErr: "x509: certificate specifies an incompatible key usage", 184 }, 185 { 186 name: "non-nested KU", 187 cert: &Certificate{ 188 SerialNumber: big.NewInt(1), 189 DNSNames: []string{"valid.testing.golang.invalid"}, 190 NotBefore: now.Add(-time.Hour), 191 NotAfter: now.Add(time.Hour), 192 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageEmailProtection}, 193 }, 194 macosErr: "x509: “valid.testing.golang.invalid” certificate is not permitted for this usage", 195 windowsErr: "x509: certificate specifies an incompatible key usage", 196 }, 197 } 198 199 leafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 200 if err != nil { 201 t.Fatalf("ecdsa.GenerateKey failed: %s", err) 202 } 203 204 for _, tc := range tests { 205 tc := tc 206 t.Run(tc.name, func(t *testing.T) { 207 t.Parallel() 208 parent := testRoot 209 if tc.selfSigned { 210 parent = tc.cert 211 } 212 certDER, err := CreateCertificate(rand.Reader, tc.cert, parent, leafKey.Public(), testRootKey) 213 if err != nil { 214 t.Fatalf("CreateCertificate failed: %s", err) 215 } 216 cert, err := ParseCertificate(certDER) 217 if err != nil { 218 t.Fatalf("ParseCertificate failed: %s", err) 219 } 220 221 var opts VerifyOptions 222 if tc.dnsName != "" { 223 opts.DNSName = tc.dnsName 224 } 225 if !tc.time.IsZero() { 226 opts.CurrentTime = tc.time 227 } 228 if len(tc.eku) > 0 { 229 opts.KeyUsages = tc.eku 230 } 231 232 expectedErr := tc.expectedErr 233 if runtime.GOOS == "darwin" && tc.macosErr != "" { 234 expectedErr = tc.macosErr 235 } else if runtime.GOOS == "windows" && tc.windowsErr != "" { 236 expectedErr = tc.windowsErr 237 } 238 239 _, err = cert.Verify(opts) 240 if err != nil && expectedErr == "" { 241 t.Errorf("unexpected verification error: %s", err) 242 } else if err != nil && !strings.HasPrefix(err.Error(), expectedErr) { 243 t.Errorf("unexpected verification error: got %q, want %q", err.Error(), expectedErr) 244 } else if err == nil && expectedErr != "" { 245 t.Errorf("unexpected verification success: want %q", expectedErr) 246 } 247 }) 248 } 249 }