Beispiel #1
0
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)
}
Beispiel #2
0
// 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
}
Beispiel #3
0
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
}
Beispiel #4
0
// 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
}
Beispiel #5
0
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
}
Beispiel #6
0
func (c *ConfigParser) open(filename string) (File, error) {
	if c.Open == nil {
		return wkfs.Open(filename)
	}
	return c.Open(filename)
}