Commit 553935a7 authored by Jonathan Pittman's avatar Jonathan Pittman

go.crypto/ssh: Implement CertTime to properly handle the "infinite" time

value ^0, which would become negative when expressed as int64.

R=agl, dave, jpsugar, hanwen
CC=golang-dev
https://codereview.appspot.com/15520047

Committer: Adam Langley <agl@golang.org>
parent 14b3e109
......@@ -35,6 +35,28 @@ type tuple struct {
Data string
}
const (
maxUint64 = 1<<64 - 1
maxInt64 = 1<<63 - 1
)
// CertTime represents an unsigned 64-bit time value in seconds starting from
// UNIX epoch. We use CertTime instead of time.Time in order to properly handle
// the "infinite" time value ^0, which would become negative when expressed as
// an int64.
type CertTime uint64
func (ct CertTime) Time() time.Time {
if ct > maxInt64 {
return time.Unix(maxInt64, 0)
}
return time.Unix(int64(ct), 0)
}
func (ct CertTime) IsInfinite() bool {
return ct == maxUint64
}
// An OpenSSHCertV01 represents an OpenSSH certificate as defined in
// [PROTOCOL.certkeys]?rev=1.8.
type OpenSSHCertV01 struct {
......@@ -44,7 +66,7 @@ type OpenSSHCertV01 struct {
Type uint32
KeyId string
ValidPrincipals []string
ValidAfter, ValidBefore time.Time
ValidAfter, ValidBefore CertTime
CriticalOptions []tuple
Extensions []tuple
Reserved []byte
......@@ -115,8 +137,8 @@ func (cert *OpenSSHCertV01) marshal(includeAlgo, includeSig bool) []byte {
r = marshalUint32(r, cert.Type)
r = marshalString(r, []byte(cert.KeyId))
r = marshalLengthPrefixedNameList(r, cert.ValidPrincipals)
r = marshalUint64(r, uint64(cert.ValidAfter.Unix()))
r = marshalUint64(r, uint64(cert.ValidBefore.Unix()))
r = marshalUint64(r, uint64(cert.ValidAfter))
r = marshalUint64(r, uint64(cert.ValidBefore))
r = marshalTupleList(r, cert.CriticalOptions)
r = marshalTupleList(r, cert.Extensions)
r = marshalString(r, cert.Reserved)
......@@ -195,13 +217,13 @@ func parseOpenSSHCertV01(in []byte, algo string) (out *OpenSSHCertV01, rest []by
if !ok {
return
}
cert.ValidAfter = time.Unix(int64(va), 0)
cert.ValidAfter = CertTime(va)
vb, in, ok := parseUint64(in)
if !ok {
return
}
cert.ValidBefore = time.Unix(int64(vb), 0)
cert.ValidBefore = CertTime(vb)
if cert.CriticalOptions, in, ok = parseTupleList(in); !ok {
return
......
......@@ -9,7 +9,6 @@ import (
"reflect"
"strings"
"testing"
"time"
)
var (
......@@ -46,9 +45,9 @@ func init() {
Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
Key: ecdsaKey.PublicKey(),
ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
ValidAfter: time.Now().Truncate(time.Second),
ValidBefore: time.Now().Truncate(time.Second).Add(time.Hour),
Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
ValidAfter: 0, // unix epoch
ValidBefore: maxUint64, // The end of currently representable time.
Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
SignatureKey: rsaKey.PublicKey(),
}
sigBytes, _ := rsaKey.Sign(rand.Reader, testCert.BytesForSigning())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment