1
// Copyright 2012 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
17
// These constants from [PROTOCOL.certkeys] represent the algorithm names
18
// for certificate types supported by this package.
20
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
21
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
22
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
23
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
24
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
27
// Certificate types distinguish between host and user
28
// certificates. The values can be set in the CertType field of
35
// Signature represents a cryptographic signature.
36
type Signature struct {
41
// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
42
// a certificate does not expire.
43
const CertTimeInfinity = 1<<64 - 1
45
// An Certificate represents an OpenSSH certificate as defined in
46
// [PROTOCOL.certkeys]?rev=1.8.
47
type Certificate struct {
53
ValidPrincipals []string
58
SignatureKey PublicKey
62
// genericCertData holds the key-independent part of the certificate data.
63
// Overall, certificates contain an nonce, public key fields and
64
// key-independent fields.
65
type genericCertData struct {
69
ValidPrincipals []byte
72
CriticalOptions []byte
79
func marshalStringList(namelist []string) []byte {
81
for _, name := range namelist {
82
s := struct{ N string }{name}
83
to = append(to, Marshal(&s)...)
88
type optionsTuple struct {
93
type optionsTupleValue struct {
97
// serialize a map of critical options or extensions
98
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
99
// we need two length prefixes for a non-empty string value
100
func marshalTuples(tups map[string]string) []byte {
101
keys := make([]string, 0, len(tups))
102
for key := range tups {
103
keys = append(keys, key)
108
for _, key := range keys {
109
s := optionsTuple{Key: key}
110
if value := tups[key]; len(value) > 0 {
111
s.Value = Marshal(&optionsTupleValue{value})
113
ret = append(ret, Marshal(&s)...)
118
// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
119
// we need two length prefixes for a non-empty option value
120
func parseTuples(in []byte) (map[string]string, error) {
121
tups := map[string]string{}
126
var key, val, extra []byte
129
if key, in, ok = parseString(in); !ok {
130
return nil, errShortRead
132
keyStr := string(key)
133
// according to [PROTOCOL.certkeys], the names must be in
135
if haveLastKey && keyStr <= lastKey {
136
return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
138
lastKey, haveLastKey = keyStr, true
139
// the next field is a data field, which if non-empty has a string embedded
140
if val, in, ok = parseString(in); !ok {
141
return nil, errShortRead
144
val, extra, ok = parseString(val)
146
return nil, errShortRead
149
return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
151
tups[keyStr] = string(val)
159
func parseCert(in []byte, privAlgo string) (*Certificate, error) {
160
nonce, rest, ok := parseString(in)
162
return nil, errShortRead
165
key, rest, err := parsePubKey(rest, privAlgo)
170
var g genericCertData
171
if err := Unmarshal(rest, &g); err != nil {
179
CertType: g.CertType,
181
ValidAfter: g.ValidAfter,
182
ValidBefore: g.ValidBefore,
185
for principals := g.ValidPrincipals; len(principals) > 0; {
186
principal, rest, ok := parseString(principals)
188
return nil, errShortRead
190
c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
194
c.CriticalOptions, err = parseTuples(g.CriticalOptions)
198
c.Extensions, err = parseTuples(g.Extensions)
202
c.Reserved = g.Reserved
203
k, err := ParsePublicKey(g.SignatureKey)
209
c.Signature, rest, ok = parseSignatureBody(g.Signature)
210
if !ok || len(rest) > 0 {
211
return nil, errors.New("ssh: signature parse error")
217
type openSSHCertSigner struct {
222
// NewCertSigner returns a Signer that signs with the given Certificate, whose
223
// private key is held by signer. It returns an error if the public key in cert
224
// doesn't match the key used by signer.
225
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
226
if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
227
return nil, errors.New("ssh: signer and cert have different public key")
230
return &openSSHCertSigner{cert, signer}, nil
233
func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
234
return s.signer.Sign(rand, data)
237
func (s *openSSHCertSigner) PublicKey() PublicKey {
241
const sourceAddressCriticalOption = "source-address"
243
// CertChecker does the work of verifying a certificate. Its methods
244
// can be plugged into ClientConfig.HostKeyCallback and
245
// ServerConfig.PublicKeyCallback. For the CertChecker to work,
246
// minimally, the IsAuthority callback should be set.
247
type CertChecker struct {
248
// SupportedCriticalOptions lists the CriticalOptions that the
249
// server application layer understands. These are only used
250
// for user certificates.
251
SupportedCriticalOptions []string
253
// IsAuthority should return true if the key is recognized as
254
// an authority. This allows for certificates to be signed by other
256
IsAuthority func(auth PublicKey) bool
258
// Clock is used for verifying time stamps. If nil, time.Now
260
Clock func() time.Time
262
// UserKeyFallback is called when CertChecker.Authenticate encounters a
263
// public key that is not a certificate. It must implement validation
264
// of user keys or else, if nil, all such keys are rejected.
265
UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
267
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
268
// public key that is not a certificate. It must implement host key
269
// validation or else, if nil, all such keys are rejected.
270
HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
272
// IsRevoked is called for each certificate so that revocation checking
273
// can be implemented. It should return true if the given certificate
274
// is revoked and false otherwise. If nil, no certificates are
275
// considered to have been revoked.
276
IsRevoked func(cert *Certificate) bool
279
// CheckHostKey checks a host key certificate. This method can be
280
// plugged into ClientConfig.HostKeyCallback.
281
func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
282
cert, ok := key.(*Certificate)
284
if c.HostKeyFallback != nil {
285
return c.HostKeyFallback(addr, remote, key)
287
return errors.New("ssh: non-certificate host key")
289
if cert.CertType != HostCert {
290
return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
293
return c.CheckCert(addr, cert)
296
// Authenticate checks a user certificate. Authenticate can be used as
297
// a value for ServerConfig.PublicKeyCallback.
298
func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
299
cert, ok := pubKey.(*Certificate)
301
if c.UserKeyFallback != nil {
302
return c.UserKeyFallback(conn, pubKey)
304
return nil, errors.New("ssh: normal key pairs not accepted")
307
if cert.CertType != UserCert {
308
return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
311
if err := c.CheckCert(conn.User(), cert); err != nil {
315
return &cert.Permissions, nil
318
// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
319
// the signature of the certificate.
320
func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
321
if c.IsRevoked != nil && c.IsRevoked(cert) {
322
return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
325
for opt, _ := range cert.CriticalOptions {
326
// sourceAddressCriticalOption will be enforced by
327
// serverAuthenticate
328
if opt == sourceAddressCriticalOption {
333
for _, supp := range c.SupportedCriticalOptions {
340
return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
344
if len(cert.ValidPrincipals) > 0 {
345
// By default, certs are valid for all users/hosts.
347
for _, p := range cert.ValidPrincipals {
354
return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
358
if !c.IsAuthority(cert.SignatureKey) {
359
return fmt.Errorf("ssh: certificate signed by unrecognized authority")
367
unixNow := clock().Unix()
368
if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
369
return fmt.Errorf("ssh: cert is not yet valid")
371
if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
372
return fmt.Errorf("ssh: cert has expired")
374
if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
375
return fmt.Errorf("ssh: certificate signature does not verify")
381
// SignCert sets c.SignatureKey to the authority's public key and stores a
382
// Signature, by authority, in the certificate.
383
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
384
c.Nonce = make([]byte, 32)
385
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
388
c.SignatureKey = authority.PublicKey()
390
sig, err := authority.Sign(rand, c.bytesForSigning())
398
var certAlgoNames = map[string]string{
399
KeyAlgoRSA: CertAlgoRSAv01,
400
KeyAlgoDSA: CertAlgoDSAv01,
401
KeyAlgoECDSA256: CertAlgoECDSA256v01,
402
KeyAlgoECDSA384: CertAlgoECDSA384v01,
403
KeyAlgoECDSA521: CertAlgoECDSA521v01,
406
// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
407
// Panics if a non-certificate algorithm is passed.
408
func certToPrivAlgo(algo string) string {
409
for privAlgo, pubAlgo := range certAlgoNames {
414
panic("unknown cert algorithm")
417
func (cert *Certificate) bytesForSigning() []byte {
421
// Drop trailing signature length.
422
return out[:len(out)-4]
425
// Marshal serializes c into OpenSSH's wire format. It is part of the
426
// PublicKey interface.
427
func (c *Certificate) Marshal() []byte {
428
generic := genericCertData{
430
CertType: c.CertType,
432
ValidPrincipals: marshalStringList(c.ValidPrincipals),
433
ValidAfter: uint64(c.ValidAfter),
434
ValidBefore: uint64(c.ValidBefore),
435
CriticalOptions: marshalTuples(c.CriticalOptions),
436
Extensions: marshalTuples(c.Extensions),
437
Reserved: c.Reserved,
438
SignatureKey: c.SignatureKey.Marshal(),
440
if c.Signature != nil {
441
generic.Signature = Marshal(c.Signature)
443
genericBytes := Marshal(&generic)
444
keyBytes := c.Key.Marshal()
445
_, keyBytes, _ = parseString(keyBytes)
446
prefix := Marshal(&struct {
449
Key []byte `ssh:"rest"`
450
}{c.Type(), c.Nonce, keyBytes})
452
result := make([]byte, 0, len(prefix)+len(genericBytes))
453
result = append(result, prefix...)
454
result = append(result, genericBytes...)
458
// Type returns the key name. It is part of the PublicKey interface.
459
func (c *Certificate) Type() string {
460
algo, ok := certAlgoNames[c.Key.Type()]
462
panic("unknown cert key type")
467
// Verify verifies a signature against the certificate's public
468
// key. It is part of the PublicKey interface.
469
func (c *Certificate) Verify(data []byte, sig *Signature) error {
470
return c.Key.Verify(data, sig)
473
func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
474
format, in, ok := parseString(in)
480
Format: string(format),
483
if out.Blob, in, ok = parseString(in); !ok {
490
func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
491
sigBytes, rest, ok := parseString(in)
496
out, trailing, ok := parseSignatureBody(sigBytes)
497
if !ok || len(trailing) > 0 {
498
return nil, nil, false