Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gen-certurl: Read SCT files from directory specified with -sctDir #259

Merged
merged 2 commits into from
Jul 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go/signedexchange/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Here, we assume that you have an access to an HTTPS server capable of serving st

1. Convert the PEM certificate to `application/cert-chain+cbor` format using `gen-certurl` tool.
```
# Fill in dummy data for OCSP/SCT, since the certificate is self-signed.
gen-certurl -pem cert.pem -ocsp <(echo ocsp) -sct <(echo sct) > cert.cbor
# Fill in dummy data for OCSP, since the certificate is self-signed.
gen-certurl -pem cert.pem -ocsp <(echo ocsp) > cert.cbor
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed -sct here since SCT is not necessary for self-signed certs.

I plan to add a separate section for instructions to create signed exchanges with trusted certificates, and will explain the usage of -sctDir there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

```

1. Host the `application/cert-chain+cbor` created in Step 3 on the HTTPS server. Configure the resource to be served with `Content-Type: application/cert-chain+cbor` HTTP header. The steps below assume the `cert.cbor` is hosted at `https://yourcdn.example.net/cert.cbor`, so substitute the URL to the actual URL in below steps.
Expand Down
38 changes: 38 additions & 0 deletions go/signedexchange/certurl/sct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package certurl

import (
"bytes"
"encoding/binary"
"fmt"
)

const maxSerializedSCTLength = 0xffff

// Serializes a list of SignedCertificateTimestamps into a
// SignedCertificateTimestampList (RFC6962 Section 3.3).
func SerializeSCTList(scts [][]byte) ([]byte, error) {
total_length := 0
for _, sct := range scts {
if len(sct) > maxSerializedSCTLength {
return nil, fmt.Errorf("SCT too large")
}
total_length += len(sct) + 2 // +2 for length
}
if total_length > maxSerializedSCTLength {
return nil, fmt.Errorf("SCT list too large")
}

var buf bytes.Buffer
if err := binary.Write(&buf, binary.BigEndian, uint16(total_length)); err != nil {
return nil, err
}
for _, sct := range scts {
if err := binary.Write(&buf, binary.BigEndian, uint16(len(sct))); err != nil {
return nil, err
}
if _, err := buf.Write(sct); err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}
37 changes: 37 additions & 0 deletions go/signedexchange/certurl/sct_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package certurl_test

import (
"bytes"
"testing"

. "github.com/WICG/webpackage/go/signedexchange/certurl"
)

func TestCreateOCSPRequest(t *testing.T) {
expected := []byte{
0x00, 0x0a, // length
0x00, 0x03, 0x01, 0x02, 0x03, // length + first SCT
0x00, 0x03, 0x04, 0x05, 0x06, // length + second SCT
}
serialized, err := SerializeSCTList([][]byte{{1, 2, 3}, {4, 5, 6}})
if err != nil {
t.Errorf("SerializeSCTList failed: %v", err)
return
}
if !bytes.Equal(expected, serialized) {
t.Errorf("The SCTs expected to serialize to %v, actual %v", expected, serialized)
}
}

func TestCreateOCSPRequestTooLarge(t *testing.T) {
_, err := SerializeSCTList([][]byte{make([]byte, 65536)})
if err == nil {
t.Errorf("SerializeSCTList didn't fail with too large SCT")
}

// (32766 + 2) * 2 = 65536
_, err = SerializeSCTList([][]byte{make([]byte, 32766), make([]byte, 32766)})
if err == nil {
t.Errorf("SerializeSCTList didn't fail with too large SCT list")
}
}
27 changes: 20 additions & 7 deletions go/signedexchange/cmd/gen-certurl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"log"
"os"
"path/filepath"

"github.com/WICG/webpackage/go/signedexchange"
"github.com/WICG/webpackage/go/signedexchange/certurl"
Expand All @@ -13,10 +14,10 @@ import (
var (
pemFilepath = flag.String("pem", "", "PEM filepath")
ocspFilepath = flag.String("ocsp", "", "DER-encoded OCSP response file. If omitted, fetched from network")
sctFilepath = flag.String("sct", "", "SCT filepath")
sctDirpath = flag.String("sctDir", "", "Directory containing .sct files")
)

func run(pemFilePath, ocspFilePath, sctFilePath string) error {
func run(pemFilePath, ocspFilePath, sctDirPath string) error {
pem, err := ioutil.ReadFile(pemFilePath)
if err != nil {
return err
Expand All @@ -39,15 +40,27 @@ func run(pemFilePath, ocspFilePath, sctFilePath string) error {
}
}

var sct []byte
if sctFilePath != "" {
sct, err = ioutil.ReadFile(sctFilePath)
var sctList []byte
if sctDirPath != "" {
files, err := filepath.Glob(filepath.Join(sctDirPath, "*.sct"))
if err != nil {
return err
}
scts := [][]byte{}
for _, file := range files {
sct, err := ioutil.ReadFile(file)
if err != nil {
return err
}
scts = append(scts, sct)
}
sctList, err = certurl.SerializeSCTList(scts)
if err != nil {
return err
}
}

out, err := certurl.CreateCertChainCBOR(certs, ocsp, sct)
out, err := certurl.CreateCertChainCBOR(certs, ocsp, sctList)
if err != nil {
return err
}
Expand All @@ -65,7 +78,7 @@ func main() {
return
}

if err := run(*pemFilepath, *ocspFilepath, *sctFilepath); err != nil {
if err := run(*pemFilepath, *ocspFilepath, *sctDirpath); err != nil {
log.Fatal(err)
}
}