Skip to content

Commit 7c76a6d

Browse files
authored
Allow >90-day cert in development. (#316)
When `-development` or `-invalidcert` is passed, a SXG cert with lifetime >90d will only cause a warning. Also, add a warning message for missing CanSignHttpExchanges extension in development.
1 parent 13e39ad commit 7c76a6d

File tree

3 files changed

+52
-30
lines changed

3 files changed

+52
-30
lines changed

cmd/amppkg/main.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ func main() {
9090
if certs == nil || len(certs) == 0 {
9191
die(fmt.Sprintf("no cert found in %s", config.CertFile))
9292
}
93-
if !(*flagDevelopment || *flagInvalidCert || util.CanSignHttpExchanges(certs[0])) {
94-
die("cert is missing CanSignHttpExchanges extension")
93+
if err := util.CanSignHttpExchanges(certs[0], time.Now()); err != nil {
94+
if *flagDevelopment || *flagInvalidCert {
95+
log.Println("WARNING:", err)
96+
} else {
97+
die(err)
98+
}
9599
}
96100

97101
key, err := util.ParsePrivateKey(keyPem)
@@ -101,7 +105,7 @@ func main() {
101105

102106
for _, urlSet := range config.URLSet {
103107
domain := urlSet.Sign.Domain
104-
if err := util.CheckCertificate(certs[0], key, domain, time.Now()); err != nil {
108+
if err := util.CertificateMatches(certs[0], key, domain); err != nil {
105109
die(errors.Wrapf(err, "checking %s", config.CertFile))
106110
}
107111
}

packager/util/util.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ func ParsePrivateKey(keyPem []byte) (crypto.PrivateKey, error) {
7171
}
7272
}
7373

74-
// CanSignHttpExchanges returns true if the given certificate has the
75-
// CanSignHttpExchanges extension. This is not the only requirement for SXGs;
76-
// it also needs to use the right public key type, which is not checked here.
77-
func CanSignHttpExchanges(cert *x509.Certificate) bool {
74+
func hasCanSignHttpExchangesExtension(cert *x509.Certificate) bool {
7875
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-cert-req
7976
for _, ext := range cert.Extensions {
8077
// 0x05, 0x00 is the DER encoding of NULL.
@@ -85,7 +82,26 @@ func CanSignHttpExchanges(cert *x509.Certificate) bool {
8582
return false
8683
}
8784

88-
func CheckCertificate(cert *x509.Certificate, priv crypto.PrivateKey, domain string, now time.Time) error {
85+
// CanSignHttpExchanges returns nil if the given certificate has the
86+
// CanSignHttpExchanges extension, and a valid lifetime per the SXG spec;
87+
// otherwise it returns an error. These are not the only requirements for SXGs;
88+
// it also needs to use the right public key type, which is not checked here.
89+
func CanSignHttpExchanges(cert *x509.Certificate, now time.Time) error {
90+
if !hasCanSignHttpExchangesExtension(cert) {
91+
return errors.New("Certificate is missing CanSignHttpExchanges extension")
92+
}
93+
94+
// TODO: remove issue date and current time check after 2019-08-01
95+
if cert.NotBefore.After(start90DayGracePeriod) || now.After(end90DayGracePeriod) {
96+
if cert.NotBefore.AddDate(0,0,90).Before(cert.NotAfter) {
97+
return errors.New("Certificate MUST have a Validity Period no greater than 90 days")
98+
}
99+
}
100+
return nil
101+
}
102+
103+
// Returns nil if the certificate matches the private key and domain, else the appropriate error.
104+
func CertificateMatches(cert *x509.Certificate, priv crypto.PrivateKey, domain string) error {
89105
certPubKey := cert.PublicKey.(*ecdsa.PublicKey)
90106
pubKey := priv.(*ecdsa.PrivateKey).PublicKey
91107
if certPubKey.Curve != pubKey.Curve {
@@ -100,11 +116,5 @@ func CheckCertificate(cert *x509.Certificate, priv crypto.PrivateKey, domain str
100116
if err := cert.VerifyHostname(domain); err != nil {
101117
return err
102118
}
103-
// TODO: remove issue date and current time check after 2019-08-01
104-
if cert.NotBefore.After(start90DayGracePeriod) || now.After(end90DayGracePeriod) {
105-
if cert.NotBefore.AddDate(0,0,90).Before(cert.NotAfter) {
106-
return errors.New("Certificate MUST have a Validity Period no greater than 90 days")
107-
}
108-
}
109119
return nil
110120
}

packager/util/util_test.go

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,48 +29,56 @@ func TestParsePrivateKey(t *testing.T) {
2929
assert.Equal(t, elliptic.P256(), pkgt.Key.(*ecdsa.PrivateKey).PublicKey.Curve)
3030
}
3131

32-
func TestCanSignHttpExchanges(t *testing.T) {
32+
func TestCanSignHttpExchangesExtension(t *testing.T) {
33+
// Before grace period, to allow the >90-day lifetime.
34+
now := time.Date(2019, time.July, 31, 0, 0, 0, 0, time.UTC)
35+
3336
// Leaf node has the extension.
34-
assert.True(t, util.CanSignHttpExchanges(pkgt.Certs[0]))
37+
assert.Nil(t, util.CanSignHttpExchanges(pkgt.Certs[0], now))
3538
// CA node does not.
36-
assert.False(t, util.CanSignHttpExchanges(pkgt.Certs[1]))
39+
assert.EqualError(t, util.CanSignHttpExchanges(pkgt.Certs[1], now), "Certificate is missing CanSignHttpExchanges extension")
3740
}
3841

3942
func TestParseCertificate(t *testing.T) {
40-
assert.Nil(t, util.CheckCertificate(pkgt.B3Certs[0], pkgt.B3Key, "amppackageexample.com", time.Now()))
43+
assert.Nil(t, util.CertificateMatches(pkgt.B3Certs[0], pkgt.B3Key, "amppackageexample.com"))
4144
}
4245

4346
func TestParseCertificateSubjectAltName(t *testing.T) {
44-
assert.Nil(t, util.CheckCertificate(pkgt.B3Certs[0], pkgt.B3Key, "www.amppackageexample.com", time.Now()))
47+
assert.Nil(t, util.CertificateMatches(pkgt.B3Certs[0], pkgt.B3Key, "www.amppackageexample.com"))
4548
}
4649

4750
func TestParseCertificateNotMatchX(t *testing.T) {
48-
assert.Contains(t, errorFrom(util.CheckCertificate(pkgt.B3Certs[0],
49-
pkgt.B3Key2, "amppackageexample.com", time.Now())), "PublicKey.X not match")
51+
assert.Contains(t, errorFrom(util.CertificateMatches(pkgt.B3Certs[0],
52+
pkgt.B3Key2, "amppackageexample.com")), "PublicKey.X not match")
5053
}
5154

5255
func TestParseCertificateNotMatchCurve(t *testing.T) {
53-
assert.Contains(t, errorFrom(util.CheckCertificate(pkgt.B3Certs[0],
54-
pkgt.B3KeyP521, "amppackageexample.com", time.Now())), "PublicKey.Curve not match")
56+
assert.Contains(t, errorFrom(util.CertificateMatches(pkgt.B3Certs[0],
57+
pkgt.B3KeyP521, "amppackageexample.com")), "PublicKey.Curve not match")
5558
}
5659

5760
func TestParseCertificateNotMatchDomain(t *testing.T) {
58-
assert.Contains(t, errorFrom(util.CheckCertificate(pkgt.B3Certs2[0],
59-
pkgt.B3Key2, "amppackageexample.com", time.Now())), "x509: certificate is valid for amppackageexample2.com, www.amppackageexample2.com, not amppackageexample.com")
61+
assert.Contains(t, errorFrom(util.CertificateMatches(pkgt.B3Certs2[0],
62+
pkgt.B3Key2, "amppackageexample.com")), "x509: certificate is valid for amppackageexample2.com, www.amppackageexample2.com, not amppackageexample.com")
63+
}
64+
65+
func TestParse90DaysCertificateAfterGracePeriod(t *testing.T) {
66+
now := time.Date(2019, time.August, 1, 0, 0, 0, 1, time.UTC)
67+
assert.Nil(t, util.CanSignHttpExchanges(pkgt.B3Certs[0], now))
6068
}
6169

6270
func TestParse91DaysCertificate(t *testing.T) {
63-
assert.Contains(t, errorFrom(util.CheckCertificate(pkgt.B3Certs91Days[0],
64-
pkgt.B3Key, "amppackageexample.com", time.Now())), "Certificate MUST have a Validity Period no greater than 90 days")
71+
assert.Contains(t, errorFrom(util.CanSignHttpExchanges(pkgt.B3Certs91Days[0],
72+
time.Now())), "Certificate MUST have a Validity Period no greater than 90 days")
6573
}
6674

6775
func TestParseCertificateIssuedBeforeMay1InGarcePeriod(t *testing.T) {
6876
now := time.Date(2019, time.July, 31, 0, 0, 0, 0, time.UTC)
69-
assert.Nil(t, util.CheckCertificate(pkgt.Certs[0], pkgt.Key, "amppackageexample.com", now))
77+
assert.Nil(t, util.CanSignHttpExchanges(pkgt.Certs[0], now))
7078
}
7179

7280
func TestParseCertificateIssuedBeforeMay1AfterGracePeriod(t *testing.T) {
7381
now := time.Date(2019, time.August, 1, 0, 0, 0, 1, time.UTC)
74-
assert.Contains(t, errorFrom(util.CheckCertificate(pkgt.Certs[0],
75-
pkgt.Key, "amppackageexample.com", now)), "Certificate MUST have a Validity Period no greater than 90 days")
82+
assert.Contains(t, errorFrom(util.CanSignHttpExchanges(pkgt.Certs[0],
83+
now)), "Certificate MUST have a Validity Period no greater than 90 days")
7684
}

0 commit comments

Comments
 (0)