func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) { b, rest := Decode(input) if b == nil { t.Fatal("failed to decode clearsign message") } if !bytes.Equal(rest, []byte("trailing")) { t.Errorf("unexpected remaining bytes returned: %s", string(rest)) } if b.ArmoredSignature.Type != "PGP SIGNATURE" { t.Errorf("bad armor type, got:%s, want:PGP SIGNATURE", b.ArmoredSignature.Type) } if !bytes.Equal(b.Bytes, []byte(expected)) { t.Errorf("bad body, got:%x want:%x", b.Bytes, expected) } if !bytes.Equal(b.Plaintext, []byte(expectedPlaintext)) { t.Errorf("bad plaintext, got:%x want:%x", b.Plaintext, expectedPlaintext) } keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey)) if err != nil { t.Errorf("failed to parse public key: %s", err) } if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil { t.Errorf("failed to check signature: %s", err) } }
func TestOpenPGPMultipleArmored(t *testing.T) { // openpgp.ReadArmoredKeyRing only returns the first key block, despite what its // comment says. Here's a test for that: r := strings.NewReader(issue454Keys) el, err := openpgp.ReadArmoredKeyRing(r) if err != nil { t.Fatal(err) } // len(el) should be 2, but it's 1: /* if len(el) != 2 { t.Errorf("number of entities: %d, expected 2", len(el)) } */ // we'll make sure that this bug still exists in openpgp, so if it ever // gets fixed we can take appropriate action: if len(el) != 1 { if len(el) == 2 { t.Errorf("openpgp.ReadArmoredKeyRing multiple keys bug fixed!") } else { t.Errorf("openpgp.ReadArmoredKeyRing bug changed...number entities: %d, expected 1.", len(el)) } } }
func TestSigning(t *testing.T) { keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey)) if err != nil { t.Errorf("failed to parse public key: %s", err) } for i, test := range signingTests { var buf bytes.Buffer plaintext, err := Encode(&buf, keyring[0].PrivateKey, nil) if err != nil { t.Errorf("#%d: error from Encode: %s", i, err) continue } if _, err := plaintext.Write([]byte(test.in)); err != nil { t.Errorf("#%d: error from Write: %s", i, err) continue } if err := plaintext.Close(); err != nil { t.Fatalf("#%d: error from Close: %s", i, err) continue } b, _ := Decode(buf.Bytes()) if b == nil { t.Errorf("#%d: failed to decode clearsign message", i) continue } if !bytes.Equal(b.Bytes, []byte(test.signed)) { t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Bytes, test.signed) continue } if !bytes.Equal(b.Plaintext, []byte(test.plaintext)) { t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Plaintext, test.plaintext) continue } if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil { t.Errorf("#%d: failed to check signature: %s", i, err) } } }
func ReadPGPFile(path string) (string, error) { if path[0] == '@' { path = path[1:] } f, err := os.Open(path) if err != nil { return "", err } defer f.Close() buf := bytes.NewBuffer(nil) _, err = buf.ReadFrom(f) if err != nil { return "", err } // First parse as an armored keyring file, if that doesn't work, treat it as a straight binary/b64 string keyReader := bytes.NewReader(buf.Bytes()) entityList, err := openpgp.ReadArmoredKeyRing(keyReader) if err == nil { if len(entityList) != 1 { return "", fmt.Errorf("more than one key found in file %s", path) } if entityList[0] == nil { return "", fmt.Errorf("primary key was nil for file %s", path) } serializedEntity := bytes.NewBuffer(nil) err = entityList[0].Serialize(serializedEntity) if err != nil { return "", fmt.Errorf("error serializing entity for file %s: %s", path, err) } return base64.StdEncoding.EncodeToString(serializedEntity.Bytes()), nil } _, err = base64.StdEncoding.DecodeString(buf.String()) if err == nil { return buf.String(), nil } return base64.StdEncoding.EncodeToString(buf.Bytes()), nil }
// note: openpgp.ReadArmoredKeyRing only returns the first block. // It will never return multiple entities. func ReadOneKeyFromString(s string) (*PGPKeyBundle, error) { s = cleanPGPInput(s) reader := strings.NewReader(s) el, err := openpgp.ReadArmoredKeyRing(reader) return finishReadOne(el, s, err) }
// note: openpgp.ReadArmoredKeyRing only returns the first block. // It will never return multiple entities. func ReadOneKeyFromString(originalArmor string) (*PGPKeyBundle, *Warnings, error) { cleanArmor := cleanPGPInput(originalArmor) reader := strings.NewReader(cleanArmor) el, err := openpgp.ReadArmoredKeyRing(reader) return finishReadOne(el, originalArmor, err) }
// FetchKeybasePubkeys fetches public keys from Keybase given a set of // usernames, which are derived from correctly formatted input entries. It // doesn't use their client code due to both the API and the fact that it is // considered alpha and probably best not to rely on it. The keys are returned // as base64-encoded strings. func FetchKeybasePubkeys(input []string) (map[string]string, error) { client := cleanhttp.DefaultClient() if client == nil { return nil, fmt.Errorf("unable to create an http client") } if len(input) == 0 { return nil, nil } usernames := make([]string, 0, len(input)) for _, v := range input { if strings.HasPrefix(v, kbPrefix) { usernames = append(usernames, strings.TrimPrefix(v, kbPrefix)) } } if len(usernames) == 0 { return nil, nil } ret := make(map[string]string, len(usernames)) url := fmt.Sprintf("https://keybase.io/_/api/1.0/user/lookup.json?usernames=%s&fields=public_keys", strings.Join(usernames, ",")) resp, err := client.Get(url) if err != nil { return nil, err } defer resp.Body.Close() type publicKeys struct { Primary struct { Bundle string } } type them struct { publicKeys `json:"public_keys"` } type kbResp struct { Status struct { Name string } Them []them } out := &kbResp{ Them: []them{}, } if err := jsonutil.DecodeJSONFromReader(resp.Body, out); err != nil { return nil, err } if out.Status.Name != "OK" { return nil, fmt.Errorf("got non-OK response: %s", out.Status.Name) } missingNames := make([]string, 0, len(usernames)) var keyReader *bytes.Reader serializedEntity := bytes.NewBuffer(nil) for i, themVal := range out.Them { if themVal.Primary.Bundle == "" { missingNames = append(missingNames, usernames[i]) continue } keyReader = bytes.NewReader([]byte(themVal.Primary.Bundle)) entityList, err := openpgp.ReadArmoredKeyRing(keyReader) if err != nil { return nil, err } if len(entityList) != 1 { return nil, fmt.Errorf("primary key could not be parsed for user %s", usernames[i]) } if entityList[0] == nil { return nil, fmt.Errorf("primary key was nil for user %s", usernames[i]) } serializedEntity.Reset() err = entityList[0].Serialize(serializedEntity) if err != nil { return nil, fmt.Errorf("error serializing entity for user %s: %s", usernames[i], err) } // The API returns values in the same ordering requested, so this should properly match ret[kbPrefix+usernames[i]] = base64.StdEncoding.EncodeToString(serializedEntity.Bytes()) } if len(missingNames) > 0 { return nil, fmt.Errorf("unable to fetch keys for user(s) %s from keybase", strings.Join(missingNames, ",")) } return ret, nil }