99package main
1010
1111import (
12+ "crypto/ecdsa"
13+ "crypto/rand"
14+ "crypto/sha256"
15+ "crypto/x509"
16+ "encoding/asn1"
17+ "encoding/base64"
1218 "encoding/json"
19+ "flag"
1320 "fmt"
1421 "io/ioutil"
1522 "log"
23+ "math/big"
1624 "net/http"
25+ "os"
1726 "sync/atomic"
27+
28+ ct "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go"
1829)
1930
31+ func createSignedSCT (leaf []byte , k * ecdsa.PrivateKey ) []byte {
32+ rawKey , _ := x509 .MarshalPKIXPublicKey (& k .PublicKey )
33+ pkHash := sha256 .Sum256 (rawKey )
34+ sct := ct.SignedCertificateTimestamp {
35+ SCTVersion : ct .V1 ,
36+ LogID : pkHash ,
37+ Timestamp : 1337 ,
38+ }
39+ serialized , _ := ct .SerializeSCTSignatureInput (sct , ct.LogEntry {
40+ Leaf : ct.MerkleTreeLeaf {
41+ LeafType : ct .TimestampedEntryLeafType ,
42+ TimestampedEntry : ct.TimestampedEntry {
43+ X509Entry : ct .ASN1Cert (leaf ),
44+ EntryType : ct .X509LogEntryType ,
45+ },
46+ },
47+ })
48+ hashed := sha256 .Sum256 (serialized )
49+ var ecdsaSig struct {
50+ R , S * big.Int
51+ }
52+ ecdsaSig .R , ecdsaSig .S , _ = ecdsa .Sign (rand .Reader , k , hashed [:])
53+ sig , _ := asn1 .Marshal (ecdsaSig )
54+
55+ ds := ct.DigitallySigned {
56+ HashAlgorithm : ct .SHA256 ,
57+ SignatureAlgorithm : ct .ECDSA ,
58+ Signature : sig ,
59+ }
60+
61+ var jsonSCTObj struct {
62+ SCTVersion ct.Version `json:"sct_version"`
63+ ID string `json:"id"`
64+ Timestamp uint64 `json:"timestamp"`
65+ Extensions string `json:"extensions"`
66+ Signature string `json:"signature"`
67+ }
68+ jsonSCTObj .SCTVersion = ct .V1
69+ jsonSCTObj .ID = base64 .StdEncoding .EncodeToString (pkHash [:])
70+ jsonSCTObj .Timestamp = 1337
71+ jsonSCTObj .Signature , _ = ds .Base64String ()
72+
73+ jsonSCT , _ := json .Marshal (jsonSCTObj )
74+ return jsonSCT
75+ }
76+
2077type ctSubmissionRequest struct {
2178 Chain []string `json:"chain"`
2279}
2380
2481type integrationSrv struct {
2582 submissions int64
83+ key * ecdsa.PrivateKey
2684}
2785
2886func (is * integrationSrv ) handler (w http.ResponseWriter , r * http.Request ) {
@@ -42,17 +100,21 @@ func (is *integrationSrv) handler(w http.ResponseWriter, r *http.Request) {
42100 if err != nil {
43101 http .Error (w , err .Error (), http .StatusBadRequest )
44102 }
103+ if len (addChainReq .Chain ) == 0 {
104+ w .WriteHeader (400 )
105+ return
106+ }
107+
108+ leaf , err := base64 .StdEncoding .DecodeString (addChainReq .Chain [0 ])
109+ if err != nil {
110+ w .WriteHeader (400 )
111+ return
112+ }
45113
46114 w .WriteHeader (http .StatusOK )
47115 // id is a sha256 of a random EC key. Generate your own with:
48116 // openssl ecparam -name prime256v1 -genkey -outform der | openssl sha256 -binary | base64
49- w .Write ([]byte (`{
50- "sct_version": 0,
51- "id": "8fjM8cvLPOhzCFwI62IYJhjkOcvWFLx1dMJbs0uhxJU=",
52- "timestamp": 1442400000,
53- "extensions": "",
54- "signature": "BAMARzBFAiBB5wKED8KqKhADT37n0y28fZIPiGbCfZRVKq0wNo0hrwIhAOIa2tPBF/rB1y30Y/ROh4LBmJ0mItAbTWy8XZKh7Wcp"
55- }` ))
117+ w .Write (createSignedSCT (leaf , is .key ))
56118 atomic .AddInt64 (& is .submissions , 1 )
57119 case "/submissions" :
58120 if r .Method != "GET" {
@@ -70,7 +132,27 @@ func (is *integrationSrv) handler(w http.ResponseWriter, r *http.Request) {
70132}
71133
72134func main () {
73- is := integrationSrv {}
135+ signingKey := flag .String ("signingKey" , "test/ct-key.pem" , "Key to use for signing SCT receipts" )
136+ flag .Parse ()
137+
138+ if * signingKey == "" {
139+ fmt .Fprintf (os .Stderr , "--signingKey is required\n " )
140+ os .Exit (1 )
141+ }
142+
143+ keyBytes , err := ioutil .ReadFile (* signingKey )
144+ if err != nil {
145+ fmt .Fprintf (os .Stderr , "failed to read signing key file\n " )
146+ return
147+ }
148+
149+ key , err := x509 .ParseECPrivateKey (keyBytes )
150+ if err != nil {
151+ fmt .Fprintf (os .Stderr , "failed to parse signing key file\n " )
152+ return
153+ }
154+
155+ is := integrationSrv {key : key }
74156 s := & http.Server {
75157 Addr : "localhost:4500" ,
76158 Handler : http .HandlerFunc (is .handler ),
0 commit comments