github.com/letsencrypt/boulder@v0.20251208.0/csr/csr_test.go (about) 1 package csr 2 3 import ( 4 "context" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/x509" 8 "crypto/x509/pkix" 9 "encoding/asn1" 10 "errors" 11 "net" 12 "net/netip" 13 "net/url" 14 "strings" 15 "testing" 16 17 "github.com/letsencrypt/boulder/core" 18 berrors "github.com/letsencrypt/boulder/errors" 19 "github.com/letsencrypt/boulder/features" 20 "github.com/letsencrypt/boulder/goodkey" 21 "github.com/letsencrypt/boulder/identifier" 22 "github.com/letsencrypt/boulder/test" 23 ) 24 25 type mockPA struct{} 26 27 func (pa *mockPA) ChallengeTypesFor(ident identifier.ACMEIdentifier) ([]core.AcmeChallenge, error) { 28 return []core.AcmeChallenge{}, nil 29 } 30 31 func (pa *mockPA) WillingToIssue(idents identifier.ACMEIdentifiers) error { 32 for _, ident := range idents { 33 if ident.Value == "bad-name.com" || ident.Value == "other-bad-name.com" { 34 return errors.New("policy forbids issuing for identifier") 35 } 36 } 37 return nil 38 } 39 40 func (pa *mockPA) ChallengeTypeEnabled(t core.AcmeChallenge) bool { 41 return true 42 } 43 44 func (pa *mockPA) CheckAuthzChallenges(a *core.Authorization) error { 45 return nil 46 } 47 48 func TestVerifyCSR(t *testing.T) { 49 private, err := rsa.GenerateKey(rand.Reader, 2048) 50 test.AssertNotError(t, err, "error generating test key") 51 signedReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{PublicKey: private.PublicKey, SignatureAlgorithm: x509.SHA256WithRSA}, private) 52 test.AssertNotError(t, err, "error generating test CSR") 53 signedReq, err := x509.ParseCertificateRequest(signedReqBytes) 54 test.AssertNotError(t, err, "error parsing test CSR") 55 brokenSignedReq := new(x509.CertificateRequest) 56 *brokenSignedReq = *signedReq 57 brokenSignedReq.Signature = []byte{1, 1, 1, 1} 58 signedReqWithHosts := new(x509.CertificateRequest) 59 *signedReqWithHosts = *signedReq 60 signedReqWithHosts.DNSNames = []string{"a.com", "b.com"} 61 signedReqWithLongCN := new(x509.CertificateRequest) 62 *signedReqWithLongCN = *signedReq 63 signedReqWithLongCN.Subject.CommonName = strings.Repeat("a", maxCNLength+1) 64 signedReqWithBadNames := new(x509.CertificateRequest) 65 *signedReqWithBadNames = *signedReq 66 signedReqWithBadNames.DNSNames = []string{"bad-name.com", "other-bad-name.com"} 67 signedReqWithEmailAddress := new(x509.CertificateRequest) 68 *signedReqWithEmailAddress = *signedReq 69 signedReqWithEmailAddress.EmailAddresses = []string{"foo@bar.com"} 70 signedReqWithIPAddress := new(x509.CertificateRequest) 71 *signedReqWithIPAddress = *signedReq 72 signedReqWithIPAddress.IPAddresses = []net.IP{net.IPv4(1, 2, 3, 4)} 73 signedReqWithIPCN := new(x509.CertificateRequest) 74 *signedReqWithIPCN = *signedReq 75 signedReqWithIPCN.Subject.CommonName = "1.2.3.4" 76 signedReqWithURI := new(x509.CertificateRequest) 77 *signedReqWithURI = *signedReq 78 testURI, _ := url.ParseRequestURI("https://example.com/") 79 signedReqWithURI.URIs = []*url.URL{testURI} 80 signedReqWithAllLongSANs := new(x509.CertificateRequest) 81 *signedReqWithAllLongSANs = *signedReq 82 signedReqWithAllLongSANs.DNSNames = []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com"} 83 84 keyPolicy, err := goodkey.NewPolicy(nil, nil) 85 test.AssertNotError(t, err, "creating test keypolicy") 86 87 cases := []struct { 88 csr *x509.CertificateRequest 89 maxNames int 90 pa core.PolicyAuthority 91 expectedError error 92 }{ 93 { 94 &x509.CertificateRequest{}, 95 100, 96 &mockPA{}, 97 invalidPubKey, 98 }, 99 { 100 &x509.CertificateRequest{PublicKey: &private.PublicKey}, 101 100, 102 &mockPA{}, 103 unsupportedSigAlg, 104 }, 105 { 106 brokenSignedReq, 107 100, 108 &mockPA{}, 109 invalidSig, 110 }, 111 { 112 signedReq, 113 100, 114 &mockPA{}, 115 invalidNoIdent, 116 }, 117 { 118 signedReqWithLongCN, 119 100, 120 &mockPA{}, 121 nil, 122 }, 123 { 124 signedReqWithHosts, 125 1, 126 &mockPA{}, 127 berrors.BadCSRError("CSR contains more than 1 identifiers"), 128 }, 129 { 130 signedReqWithBadNames, 131 100, 132 &mockPA{}, 133 errors.New("policy forbids issuing for identifier"), 134 }, 135 { 136 signedReqWithEmailAddress, 137 100, 138 &mockPA{}, 139 invalidEmailPresent, 140 }, 141 { 142 signedReqWithIPAddress, 143 100, 144 &mockPA{}, 145 nil, 146 }, 147 { 148 signedReqWithIPCN, 149 100, 150 &mockPA{}, 151 invalidIPCN, 152 }, 153 { 154 signedReqWithURI, 155 100, 156 &mockPA{}, 157 invalidURIPresent, 158 }, 159 { 160 signedReqWithAllLongSANs, 161 100, 162 &mockPA{}, 163 nil, 164 }, 165 } 166 167 for _, c := range cases { 168 err := VerifyCSR(context.Background(), c.csr, c.maxNames, &keyPolicy, c.pa) 169 test.AssertDeepEquals(t, c.expectedError, err) 170 } 171 } 172 173 func TestCNFromCSR(t *testing.T) { 174 tooLongString := strings.Repeat("a", maxCNLength+1) 175 176 cases := []struct { 177 name string 178 csr *x509.CertificateRequest 179 expectedCN string 180 }{ 181 { 182 "no explicit CN", 183 &x509.CertificateRequest{DNSNames: []string{"a.com"}}, 184 "a.com", 185 }, 186 { 187 "explicit uppercase CN", 188 &x509.CertificateRequest{Subject: pkix.Name{CommonName: "A.com"}, DNSNames: []string{"a.com"}}, 189 "a.com", 190 }, 191 { 192 "no explicit CN, uppercase SAN", 193 &x509.CertificateRequest{DNSNames: []string{"A.com"}}, 194 "a.com", 195 }, 196 { 197 "duplicate SANs", 198 &x509.CertificateRequest{DNSNames: []string{"b.com", "b.com", "a.com", "a.com"}}, 199 "b.com", 200 }, 201 { 202 "explicit CN not found in SANs", 203 &x509.CertificateRequest{Subject: pkix.Name{CommonName: "a.com"}, DNSNames: []string{"b.com"}}, 204 "a.com", 205 }, 206 { 207 "no explicit CN, all SANs too long to be the CN", 208 &x509.CertificateRequest{DNSNames: []string{ 209 tooLongString + ".a.com", 210 tooLongString + ".b.com", 211 }}, 212 "", 213 }, 214 { 215 "no explicit CN, leading SANs too long to be the CN", 216 &x509.CertificateRequest{DNSNames: []string{ 217 tooLongString + ".a.com", 218 tooLongString + ".b.com", 219 "a.com", 220 "b.com", 221 }}, 222 "a.com", 223 }, 224 { 225 "explicit CN, leading SANs too long to be the CN", 226 &x509.CertificateRequest{ 227 Subject: pkix.Name{CommonName: "A.com"}, 228 DNSNames: []string{ 229 tooLongString + ".a.com", 230 tooLongString + ".b.com", 231 "a.com", 232 "b.com", 233 }}, 234 "a.com", 235 }, 236 { 237 "explicit CN that's too long to be the CN", 238 &x509.CertificateRequest{ 239 Subject: pkix.Name{CommonName: tooLongString + ".a.com"}, 240 }, 241 "", 242 }, 243 { 244 "explicit CN that's too long to be the CN, with a SAN", 245 &x509.CertificateRequest{ 246 Subject: pkix.Name{CommonName: tooLongString + ".a.com"}, 247 DNSNames: []string{ 248 "b.com", 249 }}, 250 "", 251 }, 252 { 253 "explicit CN that's an IP", 254 &x509.CertificateRequest{ 255 Subject: pkix.Name{CommonName: "127.0.0.1"}, 256 }, 257 "", 258 }, 259 { 260 "no CN, only IP SANs", 261 &x509.CertificateRequest{ 262 IPAddresses: []net.IP{ 263 netip.MustParseAddr("127.0.0.1").AsSlice(), 264 }, 265 }, 266 "", 267 }, 268 } 269 for _, tc := range cases { 270 t.Run(tc.name, func(t *testing.T) { 271 test.AssertEquals(t, CNFromCSR(tc.csr), tc.expectedCN) 272 }) 273 } 274 } 275 276 func TestSHA1Deprecation(t *testing.T) { 277 features.Reset() 278 279 keyPolicy, err := goodkey.NewPolicy(nil, nil) 280 test.AssertNotError(t, err, "creating test keypolicy") 281 282 private, err := rsa.GenerateKey(rand.Reader, 2048) 283 test.AssertNotError(t, err, "error generating test key") 284 285 makeAndVerifyCsr := func(alg x509.SignatureAlgorithm) error { 286 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, 287 &x509.CertificateRequest{ 288 DNSNames: []string{"example.com"}, 289 SignatureAlgorithm: alg, 290 PublicKey: &private.PublicKey, 291 }, private) 292 test.AssertNotError(t, err, "creating test CSR") 293 294 csr, err := x509.ParseCertificateRequest(csrBytes) 295 test.AssertNotError(t, err, "parsing test CSR") 296 297 return VerifyCSR(context.Background(), csr, 100, &keyPolicy, &mockPA{}) 298 } 299 300 err = makeAndVerifyCsr(x509.SHA256WithRSA) 301 test.AssertNotError(t, err, "SHA256 CSR should verify") 302 303 err = makeAndVerifyCsr(x509.SHA1WithRSA) 304 test.AssertError(t, err, "SHA1 CSR should not verify") 305 } 306 307 func TestDuplicateExtensionRejection(t *testing.T) { 308 private, err := rsa.GenerateKey(rand.Reader, 2048) 309 test.AssertNotError(t, err, "error generating test key") 310 311 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, 312 &x509.CertificateRequest{ 313 DNSNames: []string{"example.com"}, 314 SignatureAlgorithm: x509.SHA256WithRSA, 315 PublicKey: &private.PublicKey, 316 ExtraExtensions: []pkix.Extension{ 317 {Id: asn1.ObjectIdentifier{2, 5, 29, 1}, Value: []byte("hello")}, 318 {Id: asn1.ObjectIdentifier{2, 5, 29, 1}, Value: []byte("world")}, 319 }, 320 }, private) 321 test.AssertNotError(t, err, "creating test CSR") 322 323 _, err = x509.ParseCertificateRequest(csrBytes) 324 test.AssertError(t, err, "CSR with duplicate extension OID should fail to parse") 325 }