Source File
certs.go
Belonging Package
golang.org/x/crypto/ssh
package ssh
import (
)
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
)
const CertTimeInfinity = 1<<64 - 1
type genericCertData struct {
Serial uint64
CertType uint32
KeyId string
ValidPrincipals []byte
ValidAfter uint64
ValidBefore uint64
CriticalOptions []byte
Extensions []byte
Reserved []byte
SignatureKey []byte
Signature []byte
}
func ( []string) []byte {
var []byte
for , := range {
:= struct{ string }{}
= append(, Marshal(&)...)
}
return
}
type optionsTuple struct {
Key string
Value []byte
}
type optionsTupleValue struct {
Value string
}
if , , = parseString(); ! {
return nil, errShortRead
}
if len() > 0 {
, , = parseString()
if ! {
return nil, errShortRead
}
if len() > 0 {
return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
}
[] = string()
} else {
[] = ""
}
}
return , nil
}
func ( []byte, string) (*Certificate, error) {
, , := parseString()
if ! {
return nil, errShortRead
}
, , := parsePubKey(, )
if != nil {
return nil,
}
var genericCertData
if := Unmarshal(, &); != nil {
return nil,
}
:= &Certificate{
Nonce: ,
Key: ,
Serial: .Serial,
CertType: .CertType,
KeyId: .KeyId,
ValidAfter: .ValidAfter,
ValidBefore: .ValidBefore,
}
for := .ValidPrincipals; len() > 0; {
, , := parseString()
if ! {
return nil, errShortRead
}
.ValidPrincipals = append(.ValidPrincipals, string())
=
}
.CriticalOptions, = parseTuples(.CriticalOptions)
if != nil {
return nil,
}
.Extensions, = parseTuples(.Extensions)
if != nil {
return nil,
}
.Reserved = .Reserved
, := ParsePublicKey(.SignatureKey)
if != nil {
return nil,
}
.SignatureKey =
.Signature, , = parseSignatureBody(.Signature)
if ! || len() > 0 {
return nil, errors.New("ssh: signature parse error")
}
return , nil
}
type openSSHCertSigner struct {
pub *Certificate
signer Signer
}
type algorithmOpenSSHCertSigner struct {
*openSSHCertSigner
algorithmSigner AlgorithmSigner
}
func ( *Certificate, Signer) (Signer, error) {
if bytes.Compare(.Key.Marshal(), .PublicKey().Marshal()) != 0 {
return nil, errors.New("ssh: signer and cert have different public key")
}
if , := .(AlgorithmSigner); {
return &algorithmOpenSSHCertSigner{
&openSSHCertSigner{, }, }, nil
} else {
return &openSSHCertSigner{, }, nil
}
}
func ( *openSSHCertSigner) ( io.Reader, []byte) (*Signature, error) {
return .signer.Sign(, )
}
func ( *openSSHCertSigner) () PublicKey {
return .pub
}
func ( *algorithmOpenSSHCertSigner) ( io.Reader, []byte, string) (*Signature, error) {
return .algorithmSigner.SignWithAlgorithm(, , )
}
const sourceAddressCriticalOption = "source-address"
IsUserAuthority func(auth PublicKey) bool
IsHostAuthority func(auth PublicKey, address string) bool
UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
IsRevoked func(cert *Certificate) bool
}
func ( *CertChecker) ( string, net.Addr, PublicKey) error {
, := .(*Certificate)
if ! {
if .HostKeyFallback != nil {
return .HostKeyFallback(, , )
}
return errors.New("ssh: non-certificate host key")
}
if .CertType != HostCert {
return fmt.Errorf("ssh: certificate presented as a host key has type %d", .CertType)
}
if !.IsHostAuthority(.SignatureKey, ) {
return fmt.Errorf("ssh: no authorities for hostname: %v", )
}
, , := net.SplitHostPort()
if != nil {
return
}
return .CheckCert(, )
}
func ( *CertChecker) ( ConnMetadata, PublicKey) (*Permissions, error) {
, := .(*Certificate)
if ! {
if .UserKeyFallback != nil {
return .UserKeyFallback(, )
}
return nil, errors.New("ssh: normal key pairs not accepted")
}
if .CertType != UserCert {
return nil, fmt.Errorf("ssh: cert has type %d", .CertType)
}
if !.IsUserAuthority(.SignatureKey) {
return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
}
if := .CheckCert(.User(), ); != nil {
return nil,
}
return &.Permissions, nil
}
func ( *CertChecker) ( string, *Certificate) error {
if .IsRevoked != nil && .IsRevoked() {
return fmt.Errorf("ssh: certificate serial %d revoked", .Serial)
}
if == sourceAddressCriticalOption {
continue
}
:= false
for , := range .SupportedCriticalOptions {
if == {
= true
break
}
}
if ! {
return fmt.Errorf("ssh: unsupported critical option %q in certificate", )
}
}
:= false
for , := range .ValidPrincipals {
if == {
= true
break
}
}
if ! {
return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", , .ValidPrincipals)
}
}
:= .Clock
if == nil {
= time.Now
}
:= ().Unix()
if := int64(.ValidAfter); < 0 || < int64(.ValidAfter) {
return fmt.Errorf("ssh: cert is not yet valid")
}
if := int64(.ValidBefore); .ValidBefore != uint64(CertTimeInfinity) && ( >= || < 0) {
return fmt.Errorf("ssh: cert has expired")
}
if := .SignatureKey.Verify(.bytesForSigning(), .Signature); != nil {
return fmt.Errorf("ssh: certificate signature does not verify")
}
return nil
}
func ( *Certificate) ( io.Reader, Signer) error {
.Nonce = make([]byte, 32)
if , := io.ReadFull(, .Nonce); != nil {
return
}
.SignatureKey = .PublicKey()
, := .Sign(, .bytesForSigning())
if != nil {
return
}
.Signature =
return nil
}
var certAlgoNames = map[string]string{
KeyAlgoRSA: CertAlgoRSAv01,
KeyAlgoDSA: CertAlgoDSAv01,
KeyAlgoECDSA256: CertAlgoECDSA256v01,
KeyAlgoECDSA384: CertAlgoECDSA384v01,
KeyAlgoECDSA521: CertAlgoECDSA521v01,
KeyAlgoSKECDSA256: CertAlgoSKECDSA256v01,
KeyAlgoED25519: CertAlgoED25519v01,
KeyAlgoSKED25519: CertAlgoSKED25519v01,
}
func ( string) string {
for , := range certAlgoNames {
if == {
return
}
}
panic("unknown cert algorithm")
}
func ( *Certificate) () []byte {
:= *
.Signature = nil
return [:len()-4]
}
func ( *Certificate) () []byte {
:= genericCertData{
Serial: .Serial,
CertType: .CertType,
KeyId: .KeyId,
ValidPrincipals: marshalStringList(.ValidPrincipals),
ValidAfter: uint64(.ValidAfter),
ValidBefore: uint64(.ValidBefore),
CriticalOptions: marshalTuples(.CriticalOptions),
Extensions: marshalTuples(.Extensions),
Reserved: .Reserved,
SignatureKey: .SignatureKey.Marshal(),
}
if .Signature != nil {
.Signature = Marshal(.Signature)
}
:= Marshal(&)
:= .Key.Marshal()
_, , _ = parseString()
:= Marshal(&struct {
string
[]byte
[]byte `ssh:"rest"`
}{.Type(), .Nonce, })
:= make([]byte, 0, len()+len())
= append(, ...)
= append(, ...)
return
}
func ( *Certificate) () string {
, := certAlgoNames[.Key.Type()]
if ! {
panic("unknown cert key type " + .Key.Type())
}
return
}
func ( *Certificate) ( []byte, *Signature) error {
return .Key.Verify(, )
}
func ( []byte) ( *Signature, []byte, bool) {
, , := parseString()
if ! {
return
}
= &Signature{
Format: string(),
}
if .Blob, , = parseString(); ! {
return
}
switch .Format {
case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01:
.Rest =
return , nil,
}
return , ,
}
func ( []byte) ( *Signature, []byte, bool) {
, , := parseString()
if ! {
return
}
, , := parseSignatureBody()
if ! || len() > 0 {
return nil, nil, false
}
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |