Skip to content

Commit 581d266

Browse files
authored
Merge pull request #321 from ampproject/master
Snapshot version 2 from master.
2 parents fadd618 + 4e25755 commit 581d266

File tree

94 files changed

+3835
-1855
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+3835
-1855
lines changed

Gopkg.lock

Lines changed: 9 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
# unused-packages = true
2626

2727

28+
ignored = ["google.golang.org/grpc"]
29+
2830
[prune]
2931
go-tests = true
3032
unused-packages = true

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,21 @@ that:
161161
possible for attackers to exploit it without intercepting the network path,
162162
for up to 7 days.
163163
164+
#### Testing productionization without a valid certificate
165+
166+
It is possible to test an otherwise fully production configuration without
167+
obtaining a certificate with the `CanSignHttpExchanges` extension. `amppkg`
168+
still needs to perform OCSP verification, so the Issuer CA must be valid (i.e. no
169+
self-signed certificates). e.g. You can use a certificate from [Let's Encrypt](https://letsencrypt.org/).
170+
171+
Running `amppkg` with the `-invalidcert` flag will skip the check for
172+
`CanSignHttpExchanges`. This flag is not necessary when using the
173+
`-development` flag.
174+
175+
Chrome can be configured to allow these invalid certificates with the
176+
*Allow Signed HTTP Exchange certificates without extension* experiment:
177+
chrome://flags/#allow-sxg-certs-without-extension
178+
164179
#### Redundancy
165180
166181
If you need to load balance across multiple instances of `amppkg`, you'll want

amppkg.example.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,16 @@ CertFile = './pems/cert.pem'
5252
KeyFile = './pems/privkey.pem'
5353

5454
# The path to a file where the OCSP response will be cached. The parent
55-
# directory should exist, but the file need not. If this is a network-mounted
56-
# file, it should support shared/exclusive locking.
55+
# directory should exist, but the file need not. A dedicated lock file will be
56+
# created in the same directory as this file, sharing the same name but with
57+
# extension .lock appended. The filesystem must support shared and exclusive
58+
# locking; consider this especially when utilizing network-mounted storage.
5759
OCSPCache = '/tmp/amppkg-ocsp'
5860

61+
# The list of request header names to be forwarded in a fetch request.
62+
# Hop-by-hop headers, conditional request headers and Via cannot be included.
63+
ForwardedRequestHeaders = []
64+
5965
# This is a simple level of validation, to guard against accidental
6066
# misconfiguration of the reverse proxy that sits in front of the packager.
6167
#

cmd/amppkg/main.go

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ import (
2424
"log"
2525
"net/http"
2626
"net/url"
27-
"path"
2827
"time"
2928

3029
"github.com/WICG/webpackage/go/signedexchange"
31-
"github.com/julienschmidt/httprouter"
3230
"github.com/pkg/errors"
3331

3432
"github.com/ampproject/amppackager/packager/certcache"
33+
"github.com/ampproject/amppackager/packager/mux"
34+
"github.com/ampproject/amppackager/packager/rtv"
3535
"github.com/ampproject/amppackager/packager/signer"
3636
"github.com/ampproject/amppackager/packager/util"
3737
"github.com/ampproject/amppackager/packager/validitymap"
38-
"github.com/ampproject/amppackager/packager/rtv"
3938
)
4039

4140
var flagConfig = flag.String("config", "amppkg.toml", "Path to the config toml file.")
4241
var flagDevelopment = flag.Bool("development", false, "True if this is a development server.")
42+
var flagInvalidCert = flag.Bool("invalidcert", false, "True if invalid certificate intentionally used in production.")
4343

4444
// Prints errors returned by pkg/errors with stack traces.
4545
func die(err interface{}) { log.Fatalf("%+v", err) }
@@ -90,16 +90,25 @@ func main() {
9090
if certs == nil || len(certs) == 0 {
9191
die(fmt.Sprintf("no cert found in %s", config.CertFile))
9292
}
93-
if !*flagDevelopment && !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
}
96-
// TODO(twifkak): Verify that certs[0] covers all the signing domains in the config.
97100

98101
key, err := util.ParsePrivateKey(keyPem)
99102
if err != nil {
100103
die(errors.Wrapf(err, "parsing %s", config.KeyFile))
101104
}
102-
// TODO(twifkak): Verify that key matches certs[0].
105+
106+
for _, urlSet := range config.URLSet {
107+
domain := urlSet.Sign.Domain
108+
if err := util.CertificateMatches(certs[0], key, domain); err != nil {
109+
die(errors.Wrapf(err, "checking %s", config.CertFile))
110+
}
111+
}
103112

104113
validityMap, err := validitymap.New()
105114
if err != nil {
@@ -125,20 +134,14 @@ func main() {
125134
}
126135
}
127136

128-
packager, err := signer.New(certs[0], key, config.URLSet, rtvCache, certCache.IsHealthy,
129-
overrideBaseURL, /*requireHeaders=*/!*flagDevelopment)
137+
signer, err := signer.New(certs[0], key, config.URLSet, rtvCache, certCache.IsHealthy,
138+
overrideBaseURL, /*requireHeaders=*/!*flagDevelopment, config.ForwardedRequestHeaders)
130139
if err != nil {
131-
die(errors.Wrap(err, "building packager"))
140+
die(errors.Wrap(err, "building signer"))
132141
}
133142

134143
// TODO(twifkak): Make log output configurable.
135-
mux := httprouter.New()
136-
mux.RedirectTrailingSlash = false
137-
mux.RedirectFixedPath = false
138-
mux.GET(util.ValidityMapPath, validityMap.ServeHTTP)
139-
mux.GET("/priv/doc", packager.ServeHTTP)
140-
mux.GET("/priv/doc/*signURL", packager.ServeHTTP)
141-
mux.GET(path.Join(util.CertURLPrefix, ":certName"), certCache.ServeHTTP)
144+
142145
addr := ""
143146
if config.LocalOnly {
144147
addr = "localhost"
@@ -148,7 +151,7 @@ func main() {
148151
Addr: addr,
149152
// Don't use DefaultServeMux, per
150153
// https://blog.cloudflare.com/exposing-go-on-the-internet/.
151-
Handler: logIntercept{mux},
154+
Handler: logIntercept{mux.New(certCache, signer, validityMap)},
152155
ReadTimeout: 10 * time.Second,
153156
ReadHeaderTimeout: 5 * time.Second,
154157
// If needing to stream the response, disable WriteTimeout and
@@ -170,6 +173,9 @@ func main() {
170173
if *flagDevelopment {
171174
log.Println("WARNING: Running in development, using SXG key for TLS. This won't work in production.")
172175
log.Fatal(server.ListenAndServeTLS(config.CertFile, config.KeyFile))
176+
} else if *flagInvalidCert {
177+
log.Println("WARNING: Running in production without valid signing certificate. Signed exchanges will not be valid.")
178+
log.Fatal(server.ListenAndServe())
173179
} else {
174180
log.Fatal(server.ListenAndServe())
175181
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
3+
export PATH=$PATH:$HOME/go/bin/
4+
5+
protoc -I . ./gateway.proto --go_out=plugins=grpc:. --proto_path .

0 commit comments

Comments
 (0)