github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/pkg/jsonsign/signhandler/sig.go (about) 1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package signhandler implements the HTTP interface to signing and verifying 18 // Camlistore JSON blobs. 19 package signhandler 20 21 import ( 22 "crypto" 23 "fmt" 24 "log" 25 "net/http" 26 "os" 27 "path/filepath" 28 "strings" 29 "sync" 30 31 "camlistore.org/pkg/blob" 32 "camlistore.org/pkg/blobserver" 33 "camlistore.org/pkg/blobserver/gethandler" 34 "camlistore.org/pkg/httputil" 35 "camlistore.org/pkg/jsonconfig" 36 "camlistore.org/pkg/jsonsign" 37 "camlistore.org/pkg/schema" 38 39 "camlistore.org/third_party/code.google.com/p/go.crypto/openpgp" 40 ) 41 42 const kMaxJSONLength = 1024 * 1024 43 44 type Handler struct { 45 // Optional path to non-standard secret gpg keyring file 46 secretRing string 47 48 pubKey string // armored 49 pubKeyBlobRef blob.Ref 50 pubKeyFetcher blob.StreamingFetcher 51 52 pubKeyBlobRefServeSuffix string // "camli/sha1-xxxx" 53 pubKeyHandler http.Handler 54 55 pubKeyDest blobserver.Storage // Where our public key is published 56 57 pubKeyUploadMu sync.RWMutex 58 pubKeyUploaded bool 59 60 entity *openpgp.Entity 61 signer *schema.Signer 62 } 63 64 func (h *Handler) Signer() *schema.Signer { return h.signer } 65 66 func (h *Handler) secretRingPath() string { 67 if h.secretRing != "" { 68 return h.secretRing 69 } 70 return filepath.Join(os.Getenv("HOME"), ".gnupg", "secring.gpg") 71 } 72 73 func init() { 74 blobserver.RegisterHandlerConstructor("jsonsign", newJSONSignFromConfig) 75 } 76 77 func newJSONSignFromConfig(ld blobserver.Loader, conf jsonconfig.Obj) (http.Handler, error) { 78 pubKeyDestPrefix := conf.OptionalString("publicKeyDest", "") 79 80 // either a short form ("26F5ABDA") or one the longer forms. 81 keyId := conf.RequiredString("keyId") 82 83 h := &Handler{ 84 secretRing: conf.OptionalString("secretRing", ""), 85 } 86 var err error 87 if err = conf.Validate(); err != nil { 88 return nil, err 89 } 90 91 h.entity, err = jsonsign.EntityFromSecring(keyId, h.secretRingPath()) 92 if err != nil { 93 return nil, err 94 } 95 96 h.pubKey, err = jsonsign.ArmoredPublicKey(h.entity) 97 98 ms := new(blob.MemoryStore) 99 h.pubKeyBlobRef, err = ms.AddBlob(crypto.SHA1, h.pubKey) 100 if err != nil { 101 return nil, err 102 } 103 h.pubKeyFetcher = ms 104 105 if pubKeyDestPrefix != "" { 106 sto, err := ld.GetStorage(pubKeyDestPrefix) 107 if err != nil { 108 return nil, err 109 } 110 h.pubKeyDest = sto 111 } 112 h.pubKeyBlobRefServeSuffix = "camli/" + h.pubKeyBlobRef.String() 113 h.pubKeyHandler = &gethandler.Handler{ 114 Fetcher: ms, 115 } 116 117 h.signer, err = schema.NewSigner(h.pubKeyBlobRef, strings.NewReader(h.pubKey), h.entity) 118 if err != nil { 119 return nil, err 120 } 121 122 return h, nil 123 } 124 125 func (h *Handler) uploadPublicKey() error { 126 h.pubKeyUploadMu.RLock() 127 if h.pubKeyUploaded { 128 h.pubKeyUploadMu.RUnlock() 129 return nil 130 } 131 h.pubKeyUploadMu.RUnlock() 132 133 sto := h.pubKeyDest 134 135 h.pubKeyUploadMu.Lock() 136 defer h.pubKeyUploadMu.Unlock() 137 if h.pubKeyUploaded { 138 return nil 139 } 140 _, err := blobserver.StatBlob(sto, h.pubKeyBlobRef) 141 if err == nil { 142 h.pubKeyUploaded = true 143 return nil 144 } 145 _, err = blobserver.Receive(sto, h.pubKeyBlobRef, strings.NewReader(h.pubKey)) 146 log.Printf("uploadPublicKey(%T, %v) = %v", sto, h.pubKeyBlobRef, err) 147 if err == nil { 148 h.pubKeyUploaded = true 149 } 150 return err 151 } 152 153 func (h *Handler) DiscoveryMap(base string) map[string]interface{} { 154 m := map[string]interface{}{ 155 "publicKeyId": h.entity.PrimaryKey.KeyIdString(), 156 "signHandler": base + "camli/sig/sign", 157 "verifyHandler": base + "camli/sig/verify", 158 } 159 if h.pubKeyBlobRef.Valid() { 160 m["publicKeyBlobRef"] = h.pubKeyBlobRef.String() 161 m["publicKey"] = base + h.pubKeyBlobRefServeSuffix 162 } 163 return m 164 } 165 166 func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 167 base := httputil.PathBase(req) 168 subPath := httputil.PathSuffix(req) 169 switch req.Method { 170 case "GET", "HEAD": 171 switch subPath { 172 case "": 173 http.Redirect(rw, req, base+"camli/sig/discovery", http.StatusFound) 174 return 175 case h.pubKeyBlobRefServeSuffix: 176 h.pubKeyHandler.ServeHTTP(rw, req) 177 return 178 case "camli/sig/sign": 179 fallthrough 180 case "camli/sig/verify": 181 http.Error(rw, "POST required", 400) 182 return 183 case "camli/sig/discovery": 184 httputil.ReturnJSON(rw, h.DiscoveryMap(base)) 185 return 186 } 187 case "POST": 188 switch subPath { 189 case "camli/sig/sign": 190 h.handleSign(rw, req) 191 return 192 case "camli/sig/verify": 193 h.handleVerify(rw, req) 194 return 195 } 196 } 197 http.Error(rw, "Unsupported path or method.", http.StatusBadRequest) 198 } 199 200 func (h *Handler) handleVerify(rw http.ResponseWriter, req *http.Request) { 201 req.ParseForm() 202 sjson := req.FormValue("sjson") 203 if sjson == "" { 204 http.Error(rw, "missing \"sjson\" parameter", http.StatusBadRequest) 205 return 206 } 207 208 m := make(map[string]interface{}) 209 210 // TODO: use a different fetcher here that checks memory, disk, 211 // the internet, etc. 212 fetcher := h.pubKeyFetcher 213 214 vreq := jsonsign.NewVerificationRequest(sjson, fetcher) 215 if vreq.Verify() { 216 m["signatureValid"] = 1 217 m["signerKeyId"] = vreq.SignerKeyId 218 m["verifiedData"] = vreq.PayloadMap 219 } else { 220 errStr := vreq.Err.Error() 221 m["signatureValid"] = 0 222 m["errorMessage"] = errStr 223 } 224 225 rw.WriteHeader(http.StatusOK) // no HTTP response code fun, error info in JSON 226 httputil.ReturnJSON(rw, m) 227 } 228 229 func (h *Handler) handleSign(rw http.ResponseWriter, req *http.Request) { 230 req.ParseForm() 231 232 badReq := func(s string) { 233 http.Error(rw, s, http.StatusBadRequest) 234 log.Printf("bad request: %s", s) 235 return 236 } 237 238 jsonStr := req.FormValue("json") 239 if jsonStr == "" { 240 badReq("missing \"json\" parameter") 241 return 242 } 243 if len(jsonStr) > kMaxJSONLength { 244 badReq("parameter \"json\" too large") 245 return 246 } 247 248 sreq := &jsonsign.SignRequest{ 249 UnsignedJSON: jsonStr, 250 Fetcher: h.pubKeyFetcher, 251 ServerMode: true, 252 SecretKeyringPath: h.secretRing, 253 } 254 signedJSON, err := sreq.Sign() 255 if err != nil { 256 // TODO: some aren't really a "bad request" 257 badReq(fmt.Sprintf("%v", err)) 258 return 259 } 260 h.uploadPublicKey() 261 rw.Write([]byte(signedJSON)) 262 } 263 264 func (h *Handler) Sign(bb *schema.Builder) (string, error) { 265 bb.SetSigner(h.pubKeyBlobRef) 266 unsigned, err := bb.JSON() 267 if err != nil { 268 return "", err 269 } 270 sreq := &jsonsign.SignRequest{ 271 UnsignedJSON: unsigned, 272 Fetcher: h.pubKeyFetcher, 273 ServerMode: true, 274 SecretKeyringPath: h.secretRing, 275 } 276 claimTime, err := bb.Blob().ClaimDate() 277 if err != nil { 278 if !schema.IsMissingField(err) { 279 return "", err 280 } 281 } else { 282 sreq.SignatureTime = claimTime 283 } 284 h.uploadPublicKey() 285 return sreq.Sign() 286 }