1
0
mirror of https://github.com/woodpecker-ci/woodpecker.git synced 2024-12-18 08:26:45 +02:00
woodpecker/vendor/code.google.com/p/go.crypto/ssh/keys.go

610 lines
14 KiB
Go
Raw Normal View History

2015-05-22 20:37:40 +02:00
// Copyright 2012 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 ssh
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
)
// These constants represent the algorithm names for key types supported by this
// package.
const (
KeyAlgoRSA = "ssh-rsa"
KeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
)
// parsePubKey parses a public key of the given algorithm.
// Use ParsePublicKey for keys with prepended algorithm.
2015-09-30 03:21:17 +02:00
func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, ok bool) {
2015-05-22 20:37:40 +02:00
switch algo {
case KeyAlgoRSA:
return parseRSA(in)
case KeyAlgoDSA:
return parseDSA(in)
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
return parseECDSA(in)
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01:
2015-09-30 03:21:17 +02:00
return parseOpenSSHCertV01(in, algo)
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
return nil, nil, false
2015-05-22 20:37:40 +02:00
}
// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
// (see sshd(8) manual page) once the options and key type fields have been
// removed.
2015-09-30 03:21:17 +02:00
func parseAuthorizedKey(in []byte) (out PublicKey, comment string, ok bool) {
2015-05-22 20:37:40 +02:00
in = bytes.TrimSpace(in)
i := bytes.IndexAny(in, " \t")
if i == -1 {
i = len(in)
}
base64Key := in[:i]
key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
n, err := base64.StdEncoding.Decode(key, base64Key)
if err != nil {
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
key = key[:n]
2015-09-30 03:21:17 +02:00
out, _, ok = ParsePublicKey(key)
if !ok {
return nil, "", false
2015-05-22 20:37:40 +02:00
}
comment = string(bytes.TrimSpace(in[i:]))
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
// ParseAuthorizedKeys parses a public key from an authorized_keys
// file used in OpenSSH according to the sshd(8) manual page.
2015-09-30 03:21:17 +02:00
func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, ok bool) {
2015-05-22 20:37:40 +02:00
for len(in) > 0 {
end := bytes.IndexByte(in, '\n')
if end != -1 {
rest = in[end+1:]
in = in[:end]
} else {
rest = nil
}
end = bytes.IndexByte(in, '\r')
if end != -1 {
in = in[:end]
}
in = bytes.TrimSpace(in)
if len(in) == 0 || in[0] == '#' {
in = rest
continue
}
i := bytes.IndexAny(in, " \t")
if i == -1 {
in = rest
continue
}
2015-09-30 03:21:17 +02:00
if out, comment, ok = parseAuthorizedKey(in[i:]); ok {
return
2015-05-22 20:37:40 +02:00
}
// No key type recognised. Maybe there's an options field at
// the beginning.
var b byte
inQuote := false
var candidateOptions []string
optionStart := 0
for i, b = range in {
isEnd := !inQuote && (b == ' ' || b == '\t')
if (b == ',' && !inQuote) || isEnd {
if i-optionStart > 0 {
candidateOptions = append(candidateOptions, string(in[optionStart:i]))
}
optionStart = i + 1
}
if isEnd {
break
}
if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
inQuote = !inQuote
}
}
for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
i++
}
if i == len(in) {
// Invalid line: unmatched quote
in = rest
continue
}
in = in[i:]
i = bytes.IndexAny(in, " \t")
if i == -1 {
in = rest
continue
}
2015-09-30 03:21:17 +02:00
if out, comment, ok = parseAuthorizedKey(in[i:]); ok {
2015-05-22 20:37:40 +02:00
options = candidateOptions
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
in = rest
continue
}
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
// ParsePublicKey parses an SSH public key formatted for use in
// the SSH wire protocol according to RFC 4253, section 6.6.
2015-09-30 03:21:17 +02:00
func ParsePublicKey(in []byte) (out PublicKey, rest []byte, ok bool) {
2015-05-22 20:37:40 +02:00
algo, in, ok := parseString(in)
if !ok {
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
return parsePubKey(in, string(algo))
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
// MarshalAuthorizedKey returns a byte stream suitable for inclusion
// in an OpenSSH authorized_keys file following the format specified
// in the sshd(8) manual page.
2015-05-22 20:37:40 +02:00
func MarshalAuthorizedKey(key PublicKey) []byte {
b := &bytes.Buffer{}
2015-09-30 03:21:17 +02:00
b.WriteString(key.PublicKeyAlgo())
2015-05-22 20:37:40 +02:00
b.WriteByte(' ')
e := base64.NewEncoder(base64.StdEncoding, b)
2015-09-30 03:21:17 +02:00
e.Write(MarshalPublicKey(key))
2015-05-22 20:37:40 +02:00
e.Close()
b.WriteByte('\n')
return b.Bytes()
}
// PublicKey is an abstraction of different types of public keys.
type PublicKey interface {
2015-09-30 03:21:17 +02:00
// PrivateKeyAlgo returns the name of the encryption system.
PrivateKeyAlgo() string
// PublicKeyAlgo returns the algorithm for the public key,
// which may be different from PrivateKeyAlgo for certificates.
PublicKeyAlgo() string
2015-05-22 20:37:40 +02:00
// Marshal returns the serialized key data in SSH wire format,
2015-09-30 03:21:17 +02:00
// without the name prefix. Callers should typically use
// MarshalPublicKey().
2015-05-22 20:37:40 +02:00
Marshal() []byte
// Verify that sig is a signature on the given data using this
// key. This function will hash the data appropriately first.
2015-09-30 03:21:17 +02:00
Verify(data []byte, sigBlob []byte) bool
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
// A Signer is can create signatures that verify against a public key.
2015-05-22 20:37:40 +02:00
type Signer interface {
// PublicKey returns an associated PublicKey instance.
PublicKey() PublicKey
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data.
2015-09-30 03:21:17 +02:00
Sign(rand io.Reader, data []byte) ([]byte, error)
2015-05-22 20:37:40 +02:00
}
type rsaPublicKey rsa.PublicKey
2015-09-30 03:21:17 +02:00
func (r *rsaPublicKey) PrivateKeyAlgo() string {
2015-05-22 20:37:40 +02:00
return "ssh-rsa"
}
2015-09-30 03:21:17 +02:00
func (r *rsaPublicKey) PublicKeyAlgo() string {
return r.PrivateKeyAlgo()
}
2015-05-22 20:37:40 +02:00
// parseRSA parses an RSA key according to RFC 4253, section 6.6.
2015-09-30 03:21:17 +02:00
func parseRSA(in []byte) (out PublicKey, rest []byte, ok bool) {
key := new(rsa.PublicKey)
2015-05-22 20:37:40 +02:00
2015-09-30 03:21:17 +02:00
bigE, in, ok := parseInt(in)
if !ok || bigE.BitLen() > 24 {
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
e := bigE.Int64()
2015-05-22 20:37:40 +02:00
if e < 3 || e&1 == 0 {
2015-09-30 03:21:17 +02:00
ok = false
return
2015-05-22 20:37:40 +02:00
}
key.E = int(e)
2015-09-30 03:21:17 +02:00
if key.N, in, ok = parseInt(in); !ok {
return
}
ok = true
return (*rsaPublicKey)(key), in, ok
2015-05-22 20:37:40 +02:00
}
func (r *rsaPublicKey) Marshal() []byte {
2015-09-30 03:21:17 +02:00
// See RFC 4253, section 6.6.
2015-05-22 20:37:40 +02:00
e := new(big.Int).SetInt64(int64(r.E))
2015-09-30 03:21:17 +02:00
length := intLength(e)
length += intLength(r.N)
ret := make([]byte, length)
rest := marshalInt(ret, e)
marshalInt(rest, r.N)
return ret
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
func (r *rsaPublicKey) Verify(data []byte, sig []byte) bool {
2015-05-22 20:37:40 +02:00
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
2015-09-30 03:21:17 +02:00
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig) == nil
2015-05-22 20:37:40 +02:00
}
type rsaPrivateKey struct {
*rsa.PrivateKey
}
func (r *rsaPrivateKey) PublicKey() PublicKey {
return (*rsaPublicKey)(&r.PrivateKey.PublicKey)
}
2015-09-30 03:21:17 +02:00
func (r *rsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
2015-05-22 20:37:40 +02:00
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
2015-09-30 03:21:17 +02:00
return rsa.SignPKCS1v15(rand, r.PrivateKey, crypto.SHA1, digest)
2015-05-22 20:37:40 +02:00
}
type dsaPublicKey dsa.PublicKey
2015-09-30 03:21:17 +02:00
func (r *dsaPublicKey) PrivateKeyAlgo() string {
2015-05-22 20:37:40 +02:00
return "ssh-dss"
}
2015-09-30 03:21:17 +02:00
func (r *dsaPublicKey) PublicKeyAlgo() string {
return r.PrivateKeyAlgo()
}
2015-05-22 20:37:40 +02:00
// parseDSA parses an DSA key according to RFC 4253, section 6.6.
2015-09-30 03:21:17 +02:00
func parseDSA(in []byte) (out PublicKey, rest []byte, ok bool) {
key := new(dsa.PublicKey)
if key.P, in, ok = parseInt(in); !ok {
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
if key.Q, in, ok = parseInt(in); !ok {
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
if key.G, in, ok = parseInt(in); !ok {
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
if key.Y, in, ok = parseInt(in); !ok {
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
ok = true
return (*dsaPublicKey)(key), in, ok
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
func (r *dsaPublicKey) Marshal() []byte {
// See RFC 4253, section 6.6.
length := intLength(r.P)
length += intLength(r.Q)
length += intLength(r.G)
length += intLength(r.Y)
ret := make([]byte, length)
rest := marshalInt(ret, r.P)
rest = marshalInt(rest, r.Q)
rest = marshalInt(rest, r.G)
marshalInt(rest, r.Y)
return ret
}
func (k *dsaPublicKey) Verify(data []byte, sigBlob []byte) bool {
2015-05-22 20:37:40 +02:00
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
// Per RFC 4253, section 6.6,
// The value for 'dss_signature_blob' is encoded as a string containing
// r, followed by s (which are 160-bit integers, without lengths or
// padding, unsigned, and in network byte order).
// For DSS purposes, sig.Blob should be exactly 40 bytes in length.
2015-09-30 03:21:17 +02:00
if len(sigBlob) != 40 {
return false
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
r := new(big.Int).SetBytes(sigBlob[:20])
s := new(big.Int).SetBytes(sigBlob[20:])
return dsa.Verify((*dsa.PublicKey)(k), digest, r, s)
2015-05-22 20:37:40 +02:00
}
type dsaPrivateKey struct {
*dsa.PrivateKey
}
func (k *dsaPrivateKey) PublicKey() PublicKey {
return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
}
2015-09-30 03:21:17 +02:00
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
2015-05-22 20:37:40 +02:00
h := crypto.SHA1.New()
h.Write(data)
digest := h.Sum(nil)
r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
if err != nil {
return nil, err
}
sig := make([]byte, 40)
2015-09-30 03:21:17 +02:00
copy(sig[:20], r.Bytes())
copy(sig[20:], s.Bytes())
return sig, nil
2015-05-22 20:37:40 +02:00
}
type ecdsaPublicKey ecdsa.PublicKey
2015-09-30 03:21:17 +02:00
func (key *ecdsaPublicKey) PrivateKeyAlgo() string {
2015-05-22 20:37:40 +02:00
return "ecdsa-sha2-" + key.nistID()
}
func (key *ecdsaPublicKey) nistID() string {
switch key.Params().BitSize {
case 256:
return "nistp256"
case 384:
return "nistp384"
case 521:
return "nistp521"
}
panic("ssh: unsupported ecdsa key size")
}
func supportedEllipticCurve(curve elliptic.Curve) bool {
2015-09-30 03:21:17 +02:00
return (curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521())
2015-05-22 20:37:40 +02:00
}
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
2015-09-30 03:21:17 +02:00
func (key *ecdsaPublicKey) PublicKeyAlgo() string {
return key.PrivateKeyAlgo()
}
2015-05-22 20:37:40 +02:00
// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
2015-09-30 03:21:17 +02:00
func parseECDSA(in []byte) (out PublicKey, rest []byte, ok bool) {
var identifier []byte
if identifier, in, ok = parseString(in); !ok {
return
2015-05-22 20:37:40 +02:00
}
key := new(ecdsa.PublicKey)
switch string(identifier) {
case "nistp256":
key.Curve = elliptic.P256()
case "nistp384":
key.Curve = elliptic.P384()
case "nistp521":
key.Curve = elliptic.P521()
default:
2015-09-30 03:21:17 +02:00
ok = false
return
2015-05-22 20:37:40 +02:00
}
var keyBytes []byte
if keyBytes, in, ok = parseString(in); !ok {
2015-09-30 03:21:17 +02:00
return
2015-05-22 20:37:40 +02:00
}
key.X, key.Y = elliptic.Unmarshal(key.Curve, keyBytes)
if key.X == nil || key.Y == nil {
2015-09-30 03:21:17 +02:00
ok = false
return
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
return (*ecdsaPublicKey)(key), in, ok
2015-05-22 20:37:40 +02:00
}
func (key *ecdsaPublicKey) Marshal() []byte {
// See RFC 5656, section 3.1.
keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y)
2015-09-30 03:21:17 +02:00
ID := key.nistID()
length := stringLength(len(ID))
length += stringLength(len(keyBytes))
2015-05-22 20:37:40 +02:00
2015-09-30 03:21:17 +02:00
ret := make([]byte, length)
r := marshalString(ret, []byte(ID))
r = marshalString(r, keyBytes)
return ret
}
2015-05-22 20:37:40 +02:00
2015-09-30 03:21:17 +02:00
func (key *ecdsaPublicKey) Verify(data []byte, sigBlob []byte) bool {
2015-05-22 20:37:40 +02:00
h := ecHash(key.Curve).New()
h.Write(data)
digest := h.Sum(nil)
// Per RFC 5656, section 3.1.2,
// The ecdsa_signature_blob value has the following specific encoding:
// mpint r
// mpint s
2015-09-30 03:21:17 +02:00
r, rest, ok := parseInt(sigBlob)
if !ok {
return false
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
s, rest, ok := parseInt(rest)
if !ok || len(rest) > 0 {
return false
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
return ecdsa.Verify((*ecdsa.PublicKey)(key), digest, r, s)
2015-05-22 20:37:40 +02:00
}
type ecdsaPrivateKey struct {
*ecdsa.PrivateKey
}
func (k *ecdsaPrivateKey) PublicKey() PublicKey {
return (*ecdsaPublicKey)(&k.PrivateKey.PublicKey)
}
2015-09-30 03:21:17 +02:00
func (k *ecdsaPrivateKey) Sign(rand io.Reader, data []byte) ([]byte, error) {
2015-05-22 20:37:40 +02:00
h := ecHash(k.PrivateKey.PublicKey.Curve).New()
h.Write(data)
digest := h.Sum(nil)
r, s, err := ecdsa.Sign(rand, k.PrivateKey, digest)
if err != nil {
return nil, err
}
sig := make([]byte, intLength(r)+intLength(s))
rest := marshalInt(sig, r)
marshalInt(rest, s)
2015-09-30 03:21:17 +02:00
return sig, nil
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
// NewPrivateKey takes a pointer to rsa, dsa or ecdsa PrivateKey
2015-05-22 20:37:40 +02:00
// returns a corresponding Signer instance. EC keys should use P256,
// P384 or P521.
func NewSignerFromKey(k interface{}) (Signer, error) {
var sshKey Signer
switch t := k.(type) {
case *rsa.PrivateKey:
sshKey = &rsaPrivateKey{t}
case *dsa.PrivateKey:
sshKey = &dsaPrivateKey{t}
case *ecdsa.PrivateKey:
if !supportedEllipticCurve(t.Curve) {
return nil, errors.New("ssh: only P256, P384 and P521 EC keys are supported.")
}
sshKey = &ecdsaPrivateKey{t}
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
// NewPublicKey takes a pointer to rsa, dsa or ecdsa PublicKey
// and returns a corresponding ssh PublicKey instance. EC keys should use P256, P384 or P521.
func NewPublicKey(k interface{}) (PublicKey, error) {
var sshKey PublicKey
switch t := k.(type) {
case *rsa.PublicKey:
sshKey = (*rsaPublicKey)(t)
case *ecdsa.PublicKey:
if !supportedEllipticCurve(t.Curve) {
return nil, errors.New("ssh: only P256, P384 and P521 EC keys are supported.")
}
sshKey = (*ecdsaPublicKey)(t)
case *dsa.PublicKey:
sshKey = (*dsaPublicKey)(t)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}
return sshKey, nil
}
2015-09-30 03:21:17 +02:00
// ParsePublicKey parses a PEM encoded private key. It supports
// PKCS#1, RSA, DSA and ECDSA private keys.
2015-05-22 20:37:40 +02:00
func ParsePrivateKey(pemBytes []byte) (Signer, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
2015-09-30 03:21:17 +02:00
var rawkey interface{}
2015-05-22 20:37:40 +02:00
switch block.Type {
case "RSA PRIVATE KEY":
2015-09-30 03:21:17 +02:00
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = rsa
2015-05-22 20:37:40 +02:00
case "EC PRIVATE KEY":
2015-09-30 03:21:17 +02:00
ec, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rawkey = ec
2015-05-22 20:37:40 +02:00
case "DSA PRIVATE KEY":
2015-09-30 03:21:17 +02:00
ec, err := parseDSAPrivate(block.Bytes)
if err != nil {
return nil, err
}
rawkey = ec
2015-05-22 20:37:40 +02:00
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
2015-09-30 03:21:17 +02:00
return NewSignerFromKey(rawkey)
2015-05-22 20:37:40 +02:00
}
2015-09-30 03:21:17 +02:00
// parseDSAPrivate parses a DSA key in ASN.1 DER encoding, as
// documented in the OpenSSL DSA manpage.
// TODO(hanwen): move this in to crypto/x509 after the Go 1.2 freeze.
func parseDSAPrivate(p []byte) (*dsa.PrivateKey, error) {
k := struct {
2015-05-22 20:37:40 +02:00
Version int
P *big.Int
Q *big.Int
G *big.Int
Priv *big.Int
Pub *big.Int
2015-09-30 03:21:17 +02:00
}{}
rest, err := asn1.Unmarshal(p, &k)
2015-05-22 20:37:40 +02:00
if err != nil {
return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
}
if len(rest) > 0 {
return nil, errors.New("ssh: garbage after DSA key")
}
return &dsa.PrivateKey{
PublicKey: dsa.PublicKey{
Parameters: dsa.Parameters{
P: k.P,
Q: k.Q,
G: k.G,
},
Y: k.Priv,
},
X: k.Pub,
}, nil
}