...
1 package csr
2
3 import (
4 "context"
5 "crypto"
6 "crypto/x509"
7 "errors"
8 "strings"
9
10 "github.com/letsencrypt/boulder/core"
11 berrors "github.com/letsencrypt/boulder/errors"
12 "github.com/letsencrypt/boulder/features"
13 "github.com/letsencrypt/boulder/goodkey"
14 "github.com/letsencrypt/boulder/identifier"
15 )
16
17
18 const maxCNLength = 64
19
20
21
22
23
24 var goodSignatureAlgorithms = map[x509.SignatureAlgorithm]bool{
25 x509.SHA256WithRSA: true,
26 x509.SHA384WithRSA: true,
27 x509.SHA512WithRSA: true,
28 x509.ECDSAWithSHA256: true,
29 x509.ECDSAWithSHA384: true,
30 x509.ECDSAWithSHA512: true,
31 }
32
33 var (
34 invalidPubKey = berrors.BadCSRError("invalid public key in CSR")
35 unsupportedSigAlg = berrors.BadCSRError("signature algorithm not supported")
36 invalidSig = berrors.BadCSRError("invalid signature on CSR")
37 invalidEmailPresent = berrors.BadCSRError("CSR contains one or more email address fields")
38 invalidIPPresent = berrors.BadCSRError("CSR contains one or more IP address fields")
39 invalidNoDNS = berrors.BadCSRError("at least one DNS name is required")
40 invalidAllSANTooLong = berrors.BadCSRError("CSR doesn't contain a SAN short enough to fit in CN")
41 )
42
43
44
45
46 func VerifyCSR(ctx context.Context, csr *x509.CertificateRequest, maxNames int, keyPolicy *goodkey.KeyPolicy, pa core.PolicyAuthority) error {
47 key, ok := csr.PublicKey.(crypto.PublicKey)
48 if !ok {
49 return invalidPubKey
50 }
51 err := keyPolicy.GoodKey(ctx, key)
52 if err != nil {
53 if errors.Is(err, goodkey.ErrBadKey) {
54 return berrors.BadCSRError("invalid public key in CSR: %s", err)
55 }
56 return berrors.InternalServerError("error checking key validity: %s", err)
57 }
58 if !goodSignatureAlgorithms[csr.SignatureAlgorithm] {
59 return unsupportedSigAlg
60 }
61
62 err = csr.CheckSignature()
63 if err != nil {
64 return invalidSig
65 }
66 if len(csr.EmailAddresses) > 0 {
67 return invalidEmailPresent
68 }
69 if len(csr.IPAddresses) > 0 {
70 return invalidIPPresent
71 }
72
73 names := NamesFromCSR(csr)
74
75 if len(names.SANs) == 0 && names.CN == "" {
76 return invalidNoDNS
77 }
78 if names.CN == "" && features.Enabled(features.RequireCommonName) {
79 return invalidAllSANTooLong
80 }
81 if len(names.CN) > maxCNLength {
82 return berrors.BadCSRError("CN was longer than %d bytes", maxCNLength)
83 }
84 if len(names.SANs) > maxNames {
85 return berrors.BadCSRError("CSR contains more than %d DNS names", maxNames)
86 }
87
88 idents := make([]identifier.ACMEIdentifier, len(names.SANs))
89 for i, name := range names.SANs {
90 idents[i] = identifier.DNSIdentifier(name)
91 }
92 err = pa.WillingToIssueWildcards(idents)
93 if err != nil {
94 return err
95 }
96 return nil
97 }
98
99 type names struct {
100 SANs []string
101 CN string
102 }
103
104
105
106
107
108
109 func NamesFromCSR(csr *x509.CertificateRequest) names {
110
111
112
113 sans := csr.DNSNames[0:len(csr.DNSNames):len(csr.DNSNames)]
114 if csr.Subject.CommonName != "" {
115 sans = append(sans, csr.Subject.CommonName)
116 }
117
118 if csr.Subject.CommonName != "" {
119 return names{SANs: core.UniqueLowerNames(sans), CN: strings.ToLower(csr.Subject.CommonName)}
120 }
121
122
123
124 for _, name := range sans {
125 if len(name) <= maxCNLength {
126 return names{SANs: core.UniqueLowerNames(sans), CN: strings.ToLower(name)}
127 }
128 }
129
130 return names{SANs: core.UniqueLowerNames(sans)}
131 }
132
View as plain text