func (fe *FileEntityFetcher) FetchEntity(keyId string) (*openpgp.Entity, error) { f, err := wkfs.Open(fe.File) if err != nil { return nil, fmt.Errorf("jsonsign: FetchEntity: %v", err) } defer f.Close() el, err := openpgp.ReadKeyRing(f) if err != nil { return nil, fmt.Errorf("jsonsign: openpgp.ReadKeyRing of %q: %v", fe.File, err) } for _, e := range el { pubk := &e.PrivateKey.PublicKey if pubk.KeyIdString() != keyId { continue } if e.PrivateKey.Encrypted { if err := fe.decryptEntity(e); err == nil { return e, nil } else { return nil, err } } return e, nil } return nil, fmt.Errorf("jsonsign: entity for keyid %q not found in %q", keyId, fe.File) }
func serveHTTP(w http.ResponseWriter, r *http.Request) { rc, err := wkfs.Open(path.Join("/gcs", gcsBucket, r.URL.Path)) if err != nil { http.Error(w, fmt.Sprintf("could not open %v: %v", r.URL.Path, err), 500) return } defer rc.Close() http.ServeContent(w, r, r.URL.Path, time.Now(), rc) }
func TestWriteRead(t *testing.T) { if !metadata.OnGCE() { t.Skipf("Not testing on GCE") } if *flagBucket == "" { t.Skipf("No bucket specified") } ctx := context.Background() cl, err := storage.NewClient(ctx) it := cl.Bucket(*flagBucket).Objects(ctx, nil) if _, err := it.Next(); err != iterator.Done { if err == nil { t.Fatalf("Bucket %v is not empty, aborting test.", *flagBucket) } t.Fatalf("unexpected bucket iteration error: %v", err) } filename := "camli-gcs_test.txt" defer func() { if err := cl.Bucket(*flagBucket).Object(filename).Delete(ctx); err != nil { t.Fatalf("error while cleaning up: %v", err) } }() // Write to camli-gcs_test.txt gcsPath := "/gcs/" + *flagBucket + "/" + filename f, err := wkfs.Create(gcsPath) if err != nil { t.Fatalf("error creating %v: %v", gcsPath, err) } data := "Hello World" if _, err := io.Copy(f, strings.NewReader(data)); err != nil { t.Fatalf("error writing to %v: %v", gcsPath, err) } if err := f.Close(); err != nil { t.Fatalf("error closing %v: %v", gcsPath, err) } // Read back from camli-gcs_test.txt g, err := wkfs.Open(gcsPath) if err != nil { t.Fatalf("error opening %v: %v", gcsPath, err) } defer g.Close() var buf bytes.Buffer if _, err := io.Copy(&buf, g); err != nil { t.Fatalf("error reading %v: %v", gcsPath, err) } if buf.String() != data { t.Fatalf("error with %v contents: got %v, wanted %v", gcsPath, buf.String(), data) } }
// KeyIdFromRing returns the public keyId contained in the secret // ring file secRing. It expects only one keyId in this secret ring // and returns an error otherwise. func KeyIdFromRing(secRing string) (keyId string, err error) { f, err := wkfs.Open(secRing) if err != nil { return "", fmt.Errorf("Could not open secret ring file %v: %v", secRing, err) } defer f.Close() el, err := openpgp.ReadKeyRing(f) if err != nil { return "", fmt.Errorf("Could not read secret ring file %s: %v", secRing, err) } if len(el) != 1 { return "", fmt.Errorf("Secret ring file %v contained %d identities; expected 1", secRing, len(el)) } ent := el[0] return ent.PrimaryKey.KeyIdShortString(), nil }
func VerifyPublicKeyFile(file, keyid string) (bool, error) { f, err := wkfs.Open(file) if err != nil { return false, err } key, err := openArmoredPublicKeyFile(f) if err != nil { return false, err } keyId := publicKeyId(key) if keyId != strings.ToUpper(keyid) { return false, fmt.Errorf("Key in file %q has id %q; expected %q", file, keyId, keyid) } return true, nil }
func publicKeyEntity(keyRing string, keyId string) (*openpgp.Entity, error) { f, err := wkfs.Open(keyRing) if err != nil { return nil, fmt.Errorf("could not open keyRing %v: %v", keyRing, err) } defer f.Close() el, err := openpgp.ReadKeyRing(f) if err != nil { return nil, err } for _, e := range el { pubk := e.PrimaryKey if pubk.KeyIdShortString() == keyId { return e, nil } } return nil, fmt.Errorf("keyId %v not found in %v", keyId, keyRing) }
func secretKeyEntity(keyRing string, keyId string) (*openpgp.Entity, error) { f, err := wkfs.Open(keyRing) if err != nil { return nil, fmt.Errorf("could not open keyRing %v: %v", keyRing, err) } defer f.Close() el, err := openpgp.ReadKeyRing(f) if err != nil { return nil, err } for _, e := range el { pubk := &e.PrivateKey.PublicKey // TODO(mpl): decrypt private key if it is passphrase-encrypted if pubk.KeyIdShortString() == keyId { return e, nil } } return nil, fmt.Errorf("keyId %v not found in %v", keyId, keyRing) }
// EntityFromSecring returns the openpgp Entity from keyFile that matches keyId. // If empty, keyFile defaults to osutil.SecretRingFile(). func EntityFromSecring(keyId, keyFile string) (*openpgp.Entity, error) { if keyId == "" { return nil, errors.New("empty keyId passed to EntityFromSecring") } keyId = strings.ToUpper(keyId) if keyFile == "" { keyFile = osutil.SecretRingFile() } secring, err := wkfs.Open(keyFile) if err != nil { return nil, fmt.Errorf("jsonsign: failed to open keyring: %v", err) } defer secring.Close() el, err := openpgp.ReadKeyRing(secring) if err != nil { return nil, fmt.Errorf("openpgp.ReadKeyRing of %q: %v", keyFile, err) } var entity *openpgp.Entity for _, e := range el { pk := e.PrivateKey if pk == nil || (pk.KeyIdString() != keyId && pk.KeyIdShortString() != keyId) { continue } entity = e } if entity == nil { found := []string{} for _, e := range el { pk := e.PrivateKey if pk == nil { continue } found = append(found, pk.KeyIdShortString()) } return nil, fmt.Errorf("didn't find a key in %q for keyId %q; other keyIds in file = %v", keyFile, keyId, found) } return entity, nil }
func (sr *SignRequest) Sign() (signedJSON string, err error) { trimmedJSON := strings.TrimRightFunc(sr.UnsignedJSON, unicode.IsSpace) // TODO: make sure these return different things inputfail := func(msg string) (string, error) { return "", errors.New(msg) } execfail := func(msg string) (string, error) { return "", errors.New(msg) } jmap := make(map[string]interface{}) if err := json.Unmarshal([]byte(trimmedJSON), &jmap); err != nil { return inputfail("json parse error") } camliSigner, hasSigner := jmap["camliSigner"] if !hasSigner { return inputfail("json lacks \"camliSigner\" key with public key blobref") } camliSignerStr, _ := camliSigner.(string) signerBlob, ok := blob.Parse(camliSignerStr) if !ok { return inputfail("json \"camliSigner\" key is malformed or unsupported") } pubkeyReader, _, err := sr.Fetcher.Fetch(signerBlob) if err != nil { // TODO: not really either an inputfail or an execfail.. but going // with exec for now. return execfail(fmt.Sprintf("failed to find public key %s: %v", signerBlob.String(), err)) } pubk, err := openArmoredPublicKeyFile(pubkeyReader) pubkeyReader.Close() if err != nil { return execfail(fmt.Sprintf("failed to parse public key from blobref %s: %v", signerBlob.String(), err)) } // This check should be redundant if the above JSON parse succeeded, but // for explicitness... if len(trimmedJSON) == 0 || trimmedJSON[len(trimmedJSON)-1] != '}' { return inputfail("json parameter lacks trailing '}'") } trimmedJSON = trimmedJSON[0 : len(trimmedJSON)-1] // sign it entityFetcher := sr.EntityFetcher if entityFetcher == nil { file := sr.secretRingPath() if file == "" { return "", errors.New("jsonsign: no EntityFetcher, and no secret ring file defined.") } secring, err := wkfs.Open(sr.secretRingPath()) if err != nil { return "", fmt.Errorf("jsonsign: failed to open secret ring file %q: %v", sr.secretRingPath(), err) } secring.Close() // just opened to see if it's readable entityFetcher = &FileEntityFetcher{File: file} } signer, err := entityFetcher.FetchEntity(pubk.KeyIdString()) if err != nil { return "", err } var buf bytes.Buffer err = openpgp.ArmoredDetachSign( &buf, signer, strings.NewReader(trimmedJSON), &packet.Config{Time: func() time.Time { return sr.SignatureTime }}, ) if err != nil { return "", err } output := buf.String() index1 := strings.Index(output, "\n\n") index2 := strings.Index(output, "\n-----") if index1 == -1 || index2 == -1 { return execfail("Failed to parse signature from gpg.") } inner := output[index1+2 : index2] signature := strings.Replace(inner, "\n", "", -1) return fmt.Sprintf("%s,\"camliSig\":\"%s\"}\n", trimmedJSON, signature), nil }
func (c *ConfigParser) open(filename string) (File, error) { if c.Open == nil { return wkfs.Open(filename) } return c.Open(filename) }