summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/note/note.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/note/note.go')
-rw-r--r--libgo/go/cmd/go/internal/note/note.go683
1 files changed, 0 insertions, 683 deletions
diff --git a/libgo/go/cmd/go/internal/note/note.go b/libgo/go/cmd/go/internal/note/note.go
deleted file mode 100644
index f770da24b37..00000000000
--- a/libgo/go/cmd/go/internal/note/note.go
+++ /dev/null
@@ -1,683 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package note defines the notes signed by the Go module database server.
-//
-// This package is part of a DRAFT of what the Go module database server will look like.
-// Do not assume the details here are final!
-//
-// A note is text signed by one or more server keys.
-// The text should be ignored unless the note is signed by
-// a trusted server key and the signature has been verified
-// using the server's public key.
-//
-// A server's public key is identified by a name, typically the "host[/path]"
-// giving the base URL of the server's transparency log.
-// The syntactic restrictions on a name are that it be non-empty,
-// well-formed UTF-8 containing neither Unicode spaces nor plus (U+002B).
-//
-// A Go module database server signs texts using public key cryptography.
-// A given server may have multiple public keys, each
-// identified by the first 32 bits of the SHA-256 hash of
-// the concatenation of the server name, a newline, and
-// the encoded public key.
-//
-// Verifying Notes
-//
-// A Verifier allows verification of signatures by one server public key.
-// It can report the name of the server and the uint32 hash of the key,
-// and it can verify a purported signature by that key.
-//
-// The standard implementation of a Verifier is constructed
-// by NewVerifier starting from a verifier key, which is a
-// plain text string of the form "<name>+<hash>+<keydata>".
-//
-// A Verifiers allows looking up a Verifier by the combination
-// of server name and key hash.
-//
-// The standard implementation of a Verifiers is constructed
-// by VerifierList from a list of known verifiers.
-//
-// A Note represents a text with one or more signatures.
-// An implementation can reject a note with too many signatures
-// (for example, more than 100 signatures).
-//
-// A Signature represents a signature on a note, verified or not.
-//
-// The Open function takes as input a signed message
-// and a set of known verifiers. It decodes and verifies
-// the message signatures and returns a Note structure
-// containing the message text and (verified or unverified) signatures.
-//
-// Signing Notes
-//
-// A Signer allows signing a text with a given key.
-// It can report the name of the server and the hash of the key
-// and can sign a raw text using that key.
-//
-// The standard implementation of a Signer is constructed
-// by NewSigner starting from an encoded signer key, which is a
-// plain text string of the form "PRIVATE+KEY+<name>+<hash>+<keydata>".
-// Anyone with an encoded signer key can sign messages using that key,
-// so it must be kept secret. The encoding begins with the literal text
-// "PRIVATE+KEY" to avoid confusion with the public server key.
-//
-// The Sign function takes as input a Note and a list of Signers
-// and returns an encoded, signed message.
-//
-// Signed Note Format
-//
-// A signed note consists of a text ending in newline (U+000A),
-// followed by a blank line (only a newline),
-// followed by one or more signature lines of this form:
-// em dash (U+2014), space (U+0020),
-// server name, space, base64-encoded signature, newline.
-//
-// Signed notes must be valid UTF-8 and must not contain any
-// ASCII control characters (those below U+0020) other than newline.
-//
-// A signature is a base64 encoding of 4+n bytes.
-//
-// The first four bytes in the signature are the uint32 key hash
-// stored in big-endian order, which is to say they are the first
-// four bytes of the truncated SHA-256 used to derive the key hash
-// in the first place.
-//
-// The remaining n bytes are the result of using the specified key
-// to sign the note text (including the final newline but not the
-// separating blank line).
-//
-// Generating Keys
-//
-// There is only one key type, Ed25519 with algorithm identifier 1.
-// New key types may be introduced in the future as needed,
-// although doing so will require deploying the new algorithms to all clients
-// before starting to depend on them for signatures.
-//
-// The GenerateKey function generates and returns a new signer
-// and corresponding verifier.
-//
-// Example
-//
-// Here is a well-formed signed note:
-//
-// If you think cryptography is the answer to your problem,
-// then you don't know what your problem is.
-//
-// — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=
-//
-// It can be constructed and displayed using:
-//
-// skey := "PRIVATE+KEY+PeterNeumann+c74f20a3+AYEKFALVFGyNhPJEMzD1QIDr+Y7hfZx09iUvxdXHKDFz"
-// text := "If you think cryptography is the answer to your problem,\n" +
-// "then you don't know what your problem is.\n"
-//
-// signer, err := note.NewSigner(skey)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// msg, err := note.Sign(&note.Note{Text: text}, signer)
-// if err != nil {
-// log.Fatal(err)
-// }
-// os.Stdout.Write(msg)
-//
-// The note's text is two lines, including the final newline,
-// and the text is purportedly signed by a server named
-// "PeterNeumann". (Although server names are canonically
-// base URLs, the only syntactic requirement is that they
-// not contain spaces or newlines).
-//
-// If Open is given access to a Verifiers including the
-// Verifier for this key, then it will succeed at verifiying
-// the encoded message and returning the parsed Note:
-//
-// vkey := "PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW"
-// msg := []byte("If you think cryptography is the answer to your problem,\n" +
-// "then you don't know what your problem is.\n" +
-// "\n" +
-// "— PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=\n")
-//
-// verifier, err := note.NewVerifier(vkey)
-// if err != nil {
-// log.Fatal(err)
-// }
-// verifiers := note.VerifierList(verifier)
-//
-// n, err := note.Open([]byte(msg), verifiers)
-// if err != nil {
-// log.Fatal(err)
-// }
-// fmt.Printf("%s (%08x):\n%s", n.Sigs[0].Name, n.Sigs[0].Hash, n.Text)
-//
-// You can add your own signature to this message by re-signing the note:
-//
-// skey, vkey, err := note.GenerateKey(rand.Reader, "EnochRoot")
-// if err != nil {
-// log.Fatal(err)
-// }
-// _ = vkey // give to verifiers
-//
-// me, err := note.NewSigner(skey)
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// msg, err := note.Sign(n, me)
-// if err != nil {
-// log.Fatal(err)
-// }
-// os.Stdout.Write(msg)
-//
-// This will print a doubly-signed message, like:
-//
-// If you think cryptography is the answer to your problem,
-// then you don't know what your problem is.
-//
-// — PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=
-// — EnochRoot rwz+eBzmZa0SO3NbfRGzPCpDckykFXSdeX+MNtCOXm2/5n2tiOHp+vAF1aGrQ5ovTG01oOTGwnWLox33WWd1RvMc+QQ=
-//
-package note
-
-import (
- "bytes"
- "crypto/ed25519"
- "crypto/sha256"
- "encoding/base64"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "strconv"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-// A Verifier verifies messages signed with a specific key.
-type Verifier interface {
- // Name returns the server name associated with the key.
- Name() string
-
- // KeyHash returns the key hash.
- KeyHash() uint32
-
- // Verify reports whether sig is a valid signature of msg.
- Verify(msg, sig []byte) bool
-}
-
-// A Signer signs messages using a specific key.
-type Signer interface {
- // Name returns the server name associated with the key.
- Name() string
-
- // KeyHash returns the key hash.
- KeyHash() uint32
-
- // Sign returns a signature for the given message.
- Sign(msg []byte) ([]byte, error)
-}
-
-// keyHash computes the key hash for the given server name and encoded public key.
-func keyHash(name string, key []byte) uint32 {
- h := sha256.New()
- h.Write([]byte(name))
- h.Write([]byte("\n"))
- h.Write(key)
- sum := h.Sum(nil)
- return binary.BigEndian.Uint32(sum)
-}
-
-var (
- errVerifierID = errors.New("malformed verifier id")
- errVerifierAlg = errors.New("unknown verifier algorithm")
- errVerifierHash = errors.New("invalid verifier hash")
-)
-
-const (
- algEd25519 = 1
-)
-
-// isValidName reports whether name is valid.
-// It must be non-empty and not have any Unicode spaces or pluses.
-func isValidName(name string) bool {
- return name != "" && utf8.ValidString(name) && strings.IndexFunc(name, unicode.IsSpace) < 0 && !strings.Contains(name, "+")
-}
-
-// NewVerifier construct a new Verifier from an encoded verifier key.
-func NewVerifier(vkey string) (Verifier, error) {
- name, vkey := chop(vkey, "+")
- hash16, key64 := chop(vkey, "+")
- hash, err1 := strconv.ParseUint(hash16, 16, 32)
- key, err2 := base64.StdEncoding.DecodeString(key64)
- if len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
- return nil, errVerifierID
- }
- if uint32(hash) != keyHash(name, key) {
- return nil, errVerifierHash
- }
-
- v := &verifier{
- name: name,
- hash: uint32(hash),
- }
-
- alg, key := key[0], key[1:]
- switch alg {
- default:
- return nil, errVerifierAlg
-
- case algEd25519:
- if len(key) != 32 {
- return nil, errVerifierID
- }
- v.verify = func(msg, sig []byte) bool {
- return ed25519.Verify(key, msg, sig)
- }
- }
-
- return v, nil
-}
-
-// chop chops s at the first instance of sep, if any,
-// and returns the text before and after sep.
-// If sep is not present, chop returns before is s and after is empty.
-func chop(s, sep string) (before, after string) {
- i := strings.Index(s, sep)
- if i < 0 {
- return s, ""
- }
- return s[:i], s[i+len(sep):]
-}
-
-// verifier is a trivial Verifier implementation.
-type verifier struct {
- name string
- hash uint32
- verify func([]byte, []byte) bool
-}
-
-func (v *verifier) Name() string { return v.name }
-func (v *verifier) KeyHash() uint32 { return v.hash }
-func (v *verifier) Verify(msg, sig []byte) bool { return v.verify(msg, sig) }
-
-// NewSigner constructs a new Signer from an encoded signer key.
-func NewSigner(skey string) (Signer, error) {
- priv1, skey := chop(skey, "+")
- priv2, skey := chop(skey, "+")
- name, skey := chop(skey, "+")
- hash16, key64 := chop(skey, "+")
- hash, err1 := strconv.ParseUint(hash16, 16, 32)
- key, err2 := base64.StdEncoding.DecodeString(key64)
- if priv1 != "PRIVATE" || priv2 != "KEY" || len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
- return nil, errSignerID
- }
-
- // Note: hash is the hash of the public key and we have the private key.
- // Must verify hash after deriving public key.
-
- s := &signer{
- name: name,
- hash: uint32(hash),
- }
-
- var pubkey []byte
-
- alg, key := key[0], key[1:]
- switch alg {
- default:
- return nil, errSignerAlg
-
- case algEd25519:
- if len(key) != 32 {
- return nil, errSignerID
- }
- key = ed25519.NewKeyFromSeed(key)
- pubkey = append([]byte{algEd25519}, key[32:]...)
- s.sign = func(msg []byte) ([]byte, error) {
- return ed25519.Sign(key, msg), nil
- }
- }
-
- if uint32(hash) != keyHash(name, pubkey) {
- return nil, errSignerHash
- }
-
- return s, nil
-}
-
-var (
- errSignerID = errors.New("malformed verifier id")
- errSignerAlg = errors.New("unknown verifier algorithm")
- errSignerHash = errors.New("invalid verifier hash")
-)
-
-// signer is a trivial Signer implementation.
-type signer struct {
- name string
- hash uint32
- sign func([]byte) ([]byte, error)
-}
-
-func (s *signer) Name() string { return s.name }
-func (s *signer) KeyHash() uint32 { return s.hash }
-func (s *signer) Sign(msg []byte) ([]byte, error) { return s.sign(msg) }
-
-// GenerateKey generates a signer and verifier key pair for a named server.
-// The signer key skey is private and must be kept secret.
-func GenerateKey(rand io.Reader, name string) (skey, vkey string, err error) {
- pub, priv, err := ed25519.GenerateKey(rand)
- if err != nil {
- return "", "", err
- }
- pubkey := append([]byte{algEd25519}, pub...)
- privkey := append([]byte{algEd25519}, priv.Seed()...)
- h := keyHash(name, pubkey)
-
- skey = fmt.Sprintf("PRIVATE+KEY+%s+%08x+%s", name, h, base64.StdEncoding.EncodeToString(privkey))
- vkey = fmt.Sprintf("%s+%08x+%s", name, h, base64.StdEncoding.EncodeToString(pubkey))
- return skey, vkey, nil
-}
-
-// NewEd25519VerifierKey returns an encoded verifier key using the given name
-// and Ed25519 public key.
-func NewEd25519VerifierKey(name string, key ed25519.PublicKey) (string, error) {
- if len(key) != ed25519.PublicKeySize {
- return "", fmt.Errorf("invalid public key size %d, expected %d", len(key), ed25519.PublicKeySize)
- }
-
- pubkey := append([]byte{algEd25519}, key...)
- hash := keyHash(name, pubkey)
-
- b64Key := base64.StdEncoding.EncodeToString(pubkey)
- return fmt.Sprintf("%s+%08x+%s", name, hash, b64Key), nil
-}
-
-// A Verifiers is a collection of known verifier keys.
-type Verifiers interface {
- // Verifier returns the Verifier associated with the key
- // identified by the name and hash.
- // If the name, hash pair is unknown, Verifier should return
- // an UnknownVerifierError.
- Verifier(name string, hash uint32) (Verifier, error)
-}
-
-// An UnknownVerifierError indicates that the given key is not known.
-// The Open function records signatures without associated verifiers as
-// unverified signatures.
-type UnknownVerifierError struct {
- Name string
- KeyHash uint32
-}
-
-func (e *UnknownVerifierError) Error() string {
- return fmt.Sprintf("unknown key %s+%08x", e.Name, e.KeyHash)
-}
-
-// An ambiguousVerifierError indicates that the given name and hash
-// match multiple keys passed to VerifierList.
-// (If this happens, some malicious actor has taken control of the
-// verifier list, at which point we may as well give up entirely,
-// but we diagnose the problem instead.)
-type ambiguousVerifierError struct {
- name string
- hash uint32
-}
-
-func (e *ambiguousVerifierError) Error() string {
- return fmt.Sprintf("ambiguous key %s+%08x", e.name, e.hash)
-}
-
-// VerifierList returns a Verifiers implementation that uses the given list of verifiers.
-func VerifierList(list ...Verifier) Verifiers {
- m := make(verifierMap)
- for _, v := range list {
- k := nameHash{v.Name(), v.KeyHash()}
- m[k] = append(m[k], v)
- }
- return m
-}
-
-type nameHash struct {
- name string
- hash uint32
-}
-
-type verifierMap map[nameHash][]Verifier
-
-func (m verifierMap) Verifier(name string, hash uint32) (Verifier, error) {
- v, ok := m[nameHash{name, hash}]
- if !ok {
- return nil, &UnknownVerifierError{name, hash}
- }
- if len(v) > 1 {
- return nil, &ambiguousVerifierError{name, hash}
- }
- return v[0], nil
-}
-
-// A Note is a text and signatures.
-type Note struct {
- Text string // text of note
- Sigs []Signature // verified signatures
- UnverifiedSigs []Signature // unverified signatures
-}
-
-// A Signature is a single signature found in a note.
-type Signature struct {
- // Name and Hash give the name and key hash
- // for the key that generated the signature.
- Name string
- Hash uint32
-
- // Base64 records the base64-encoded signature bytes.
- Base64 string
-}
-
-// An UnverifiedNoteError indicates that the note
-// successfully parsed but had no verifiable signatures.
-type UnverifiedNoteError struct {
- Note *Note
-}
-
-func (e *UnverifiedNoteError) Error() string {
- return "note has no verifiable signatures"
-}
-
-// An InvalidSignatureError indicates that the given key was known
-// and the associated Verifier rejected the signature.
-type InvalidSignatureError struct {
- Name string
- Hash uint32
-}
-
-func (e *InvalidSignatureError) Error() string {
- return fmt.Sprintf("invalid signature for key %s+%08x", e.Name, e.Hash)
-}
-
-var (
- errMalformedNote = errors.New("malformed note")
- errInvalidSigner = errors.New("invalid signer")
-
- sigSplit = []byte("\n\n")
- sigPrefix = []byte("— ")
-)
-
-// Open opens and parses the message msg, checking signatures from the known verifiers.
-//
-// For each signature in the message, Open calls known.Verifier to find a verifier.
-// If known.Verifier returns a verifier and the verifier accepts the signature,
-// Open records the signature in the returned note's Sigs field.
-// If known.Verifier returns a verifier but the verifier rejects the signature,
-// Open returns an InvalidSignatureError.
-// If known.Verifier returns an UnknownVerifierError,
-// Open records the signature in the returned note's UnverifiedSigs field.
-// If known.Verifier returns any other error, Open returns that error.
-//
-// If no known verifier has signed an otherwise valid note,
-// Open returns an UnverifiedNoteError.
-// In this case, the unverified note can be fetched from inside the error.
-func Open(msg []byte, known Verifiers) (*Note, error) {
- if known == nil {
- // Treat nil Verifiers as empty list, to produce useful error instead of crash.
- known = VerifierList()
- }
-
- // Must have valid UTF-8 with no non-newline ASCII control characters.
- for i := 0; i < len(msg); {
- r, size := utf8.DecodeRune(msg[i:])
- if r < 0x20 && r != '\n' || r == utf8.RuneError && size == 1 {
- return nil, errMalformedNote
- }
- i += size
- }
-
- // Must end with signature block preceded by blank line.
- split := bytes.LastIndex(msg, sigSplit)
- if split < 0 {
- return nil, errMalformedNote
- }
- text, sigs := msg[:split+1], msg[split+2:]
- if len(sigs) == 0 || sigs[len(sigs)-1] != '\n' {
- return nil, errMalformedNote
- }
-
- n := &Note{
- Text: string(text),
- }
-
- var buf bytes.Buffer
- buf.Write(text)
-
- // Parse and verify signatures.
- // Ignore duplicate signatures.
- seen := make(map[nameHash]bool)
- seenUnverified := make(map[string]bool)
- numSig := 0
- for len(sigs) > 0 {
- // Pull out next signature line.
- // We know sigs[len(sigs)-1] == '\n', so IndexByte always finds one.
- i := bytes.IndexByte(sigs, '\n')
- line := sigs[:i]
- sigs = sigs[i+1:]
-
- if !bytes.HasPrefix(line, sigPrefix) {
- return nil, errMalformedNote
- }
- line = line[len(sigPrefix):]
- name, b64 := chop(string(line), " ")
- sig, err := base64.StdEncoding.DecodeString(b64)
- if err != nil || !isValidName(name) || b64 == "" || len(sig) < 5 {
- return nil, errMalformedNote
- }
- hash := binary.BigEndian.Uint32(sig[0:4])
- sig = sig[4:]
-
- if numSig++; numSig > 100 {
- // Avoid spending forever parsing a note with many signatures.
- return nil, errMalformedNote
- }
-
- v, err := known.Verifier(name, hash)
- if _, ok := err.(*UnknownVerifierError); ok {
- // Drop repeated identical unverified signatures.
- if seenUnverified[string(line)] {
- continue
- }
- seenUnverified[string(line)] = true
- n.UnverifiedSigs = append(n.UnverifiedSigs, Signature{Name: name, Hash: hash, Base64: b64})
- continue
- }
- if err != nil {
- return nil, err
- }
-
- // Drop repeated signatures by a single verifier.
- if seen[nameHash{name, hash}] {
- continue
- }
- seen[nameHash{name, hash}] = true
-
- ok := v.Verify(text, sig)
- if !ok {
- return nil, &InvalidSignatureError{name, hash}
- }
-
- n.Sigs = append(n.Sigs, Signature{Name: name, Hash: hash, Base64: b64})
- }
-
- // Parsed and verified all the signatures.
- if len(n.Sigs) == 0 {
- return nil, &UnverifiedNoteError{n}
- }
- return n, nil
-}
-
-// Sign signs the note with the given signers and returns the encoded message.
-// The new signatures from signers are listed in the encoded message after
-// the existing signatures already present in n.Sigs.
-// If any signer uses the same key as an existing signature,
-// the existing signature is elided from the output.
-func Sign(n *Note, signers ...Signer) ([]byte, error) {
- var buf bytes.Buffer
- if !strings.HasSuffix(n.Text, "\n") {
- return nil, errMalformedNote
- }
- buf.WriteString(n.Text)
-
- // Prepare signatures.
- var sigs bytes.Buffer
- have := make(map[nameHash]bool)
- for _, s := range signers {
- name := s.Name()
- hash := s.KeyHash()
- have[nameHash{name, hash}] = true
- if !isValidName(name) {
- return nil, errInvalidSigner
- }
-
- sig, err := s.Sign(buf.Bytes()) // buf holds n.Text
- if err != nil {
- return nil, err
- }
-
- var hbuf [4]byte
- binary.BigEndian.PutUint32(hbuf[:], hash)
- b64 := base64.StdEncoding.EncodeToString(append(hbuf[:], sig...))
- sigs.WriteString("— ")
- sigs.WriteString(name)
- sigs.WriteString(" ")
- sigs.WriteString(b64)
- sigs.WriteString("\n")
- }
-
- buf.WriteString("\n")
-
- // Emit existing signatures not replaced by new ones.
- for _, list := range [][]Signature{n.Sigs, n.UnverifiedSigs} {
- for _, sig := range list {
- name, hash := sig.Name, sig.Hash
- if !isValidName(name) {
- return nil, errMalformedNote
- }
- if have[nameHash{name, hash}] {
- continue
- }
- // Double-check hash against base64.
- raw, err := base64.StdEncoding.DecodeString(sig.Base64)
- if err != nil || len(raw) < 4 || binary.BigEndian.Uint32(raw) != hash {
- return nil, errMalformedNote
- }
- buf.WriteString("— ")
- buf.WriteString(sig.Name)
- buf.WriteString(" ")
- buf.WriteString(sig.Base64)
- buf.WriteString("\n")
- }
- }
- buf.Write(sigs.Bytes())
-
- return buf.Bytes(), nil
-}