kosx

certs.go

Dec 27th, 2020
1,032
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.
  4. package ssh
  5. import (
  6.     "bytes"
  7.     "errors"
  8.     "fmt"
  9.     "io"
  10.     "net"
  11.     "sort"
  12.     "time"
  13. )
  14. // These constants from [PROTOCOL.certkeys] represent the algorithm names
  15. // for certificate types supported by this package.
  16. const (
  17.     CertAlgoRSAv01        = "ssh-rsa-cert-v01@openssh.com"
  18.     CertAlgoDSAv01        = "ssh-dss-cert-v01@openssh.com"
  19.     CertAlgoECDSA256v01   = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
  20.     CertAlgoECDSA384v01   = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
  21.     CertAlgoECDSA521v01   = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
  22.     CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
  23.     CertAlgoED25519v01    = "ssh-ed25519-cert-v01@openssh.com"
  24.     CertAlgoSKED25519v01  = "sk-ssh-ed25519-cert-v01@openssh.com"
  25. )
  26. // Certificate types distinguish between host and user
  27. // certificates. The values can be set in the CertType field of
  28. // Certificate.
  29. const (
  30.     UserCert = 1
  31.     HostCert = 2
  32. )
  33. // Signature represents a cryptographic signature.
  34. type Signature struct {
  35.     Format string
  36.     Blob   []byte
  37.     Rest   []byte `ssh:"rest"`
  38. }
  39. // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
  40. // a certificate does not expire.
  41. const CertTimeInfinity = 1<<64 - 1
  42. // An Certificate represents an OpenSSH certificate as defined in
  43. // [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
  44. // PublicKey interface, so it can be unmarshaled using
  45. // ParsePublicKey.
  46. type Certificate struct {
  47.     Nonce           []byte
  48.     Key             PublicKey
  49.     Serial          uint64
  50.     CertType        uint32
  51.     KeyId           string
  52.     ValidPrincipals []string
  53.     ValidAfter      uint64
  54.     ValidBefore     uint64
  55.     Permissions
  56.     Reserved     []byte
  57.     SignatureKey PublicKey
  58.     Signature    *Signature
  59. }
  60. // genericCertData holds the key-independent part of the certificate data.
  61. // Overall, certificates contain an nonce, public key fields and
  62. // key-independent fields.
  63. type genericCertData struct {
  64.     Serial          uint64
  65.     CertType        uint32
  66.     KeyId           string
  67.     ValidPrincipals []byte
  68.     ValidAfter      uint64
  69.     ValidBefore     uint64
  70.     CriticalOptions []byte
  71.     Extensions      []byte
  72.     Reserved        []byte
  73.     SignatureKey    []byte
  74.     Signature       []byte
  75. }
  76. func marshalStringList(namelist []string) []byte {
  77.     var to []byte
  78.     for _, name := range namelist {
  79.         s := struct{ N string }{name}
  80.         to = append(to, Marshal(&s)...)
  81.     }
  82.     return to
  83. }
  84. type optionsTuple struct {
  85.     Key   string
  86.     Value []byte
  87. }
  88. type optionsTupleValue struct {
  89.     Value string
  90. }
  91. // serialize a map of critical options or extensions
  92. // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
  93. // we need two length prefixes for a non-empty string value
  94. func marshalTuples(tups map[string]string) []byte {
  95.     keys := make([]string, 0, len(tups))
  96.     for key := range tups {
  97.         keys = append(keys, key)
  98.     }
  99.     sort.Strings(keys)
  100.     var ret []byte
  101.     for _, key := range keys {
  102.         s := optionsTuple{Key: key}
  103.         if value := tups[key]; len(value) > 0 {
  104.             s.Value = Marshal(&optionsTupleValue{value})
  105.         }
  106.         ret = append(ret, Marshal(&s)...)
  107.     }
  108.     return ret
  109. }
  110. // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
  111. // we need two length prefixes for a non-empty option value
  112. func parseTuples(in []byte) (map[string]string, error) {
  113.     tups := map[string]string{}
  114.     var lastKey string
  115.     var haveLastKey bool
  116.     for len(in) > 0 {
  117.         var key, val, extra []byte
  118.         var ok bool
  119.         if key, in, ok = parseString(in); !ok {
  120.             return nil, errShortRead
  121.         }
  122.         keyStr := string(key)
  123.         // according to [PROTOCOL.certkeys], the names must be in
  124.         // lexical order.
  125.         if haveLastKey && keyStr <= lastKey {
  126.             return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
  127.         }
  128.         lastKey, haveLastKey = keyStr, true
  129.         // the next field is a data field, which if non-empty has a string embedded
  130.         if val, in, ok = parseString(in); !ok {
  131.             return nil, errShortRead
  132.         }
  133.         if len(val) > 0 {
  134.             val, extra, ok = parseString(val)
  135.             if !ok {
  136.                 return nil, errShortRead
  137.             }
  138.             if len(extra) > 0 {
  139.                 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
  140.             }
  141.             tups[keyStr] = string(val)
  142.         } else {
  143.             tups[keyStr] = ""
  144.         }
  145.     }
  146.     return tups, nil
  147. }
  148. func parseCert(in []byte, privAlgo string) (*Certificate, error) {
  149.     nonce, rest, ok := parseString(in)
  150.     if !ok {
  151.         return nil, errShortRead
  152.     }
  153.     key, rest, err := parsePubKey(rest, privAlgo)
  154.     if err != nil {
  155.         return nil, err
  156.     }
  157.     var g genericCertData
  158.     if err := Unmarshal(rest, &g); err != nil {
  159.         return nil, err
  160.     }
  161.     c := &Certificate{
  162.         Nonce:       nonce,
  163.         Key:         key,
  164.         Serial:      g.Serial,
  165.         CertType:    g.CertType,
  166.         KeyId:       g.KeyId,
  167.         ValidAfter:  g.ValidAfter,
  168.         ValidBefore: g.ValidBefore,
  169.     }
  170.     for principals := g.ValidPrincipals; len(principals) > 0; {
  171.         principal, rest, ok := parseString(principals)
  172.         if !ok {
  173.             return nil, errShortRead
  174.         }
  175.         c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
  176.         principals = rest
  177.     }
  178.     c.CriticalOptions, err = parseTuples(g.CriticalOptions)
  179.     if err != nil {
  180.         return nil, err
  181.     }
  182.     c.Extensions, err = parseTuples(g.Extensions)
  183.     if err != nil {
  184.         return nil, err
  185.     }
  186.     c.Reserved = g.Reserved
  187.     k, err := ParsePublicKey(g.SignatureKey)
  188.     if err != nil {
  189.         return nil, err
  190.     }
  191.     c.SignatureKey = k
  192.     c.Signature, rest, ok = parseSignatureBody(g.Signature)
  193.     if !ok || len(rest) > 0 {
  194.         return nil, errors.New("ssh: signature parse error")
  195.     }
  196.     return c, nil
  197. }
  198. type openSSHCertSigner struct {
  199.     pub    *Certificate
  200.     signer Signer
  201. }
  202. type algorithmOpenSSHCertSigner struct {
  203.     *openSSHCertSigner
  204.     algorithmSigner AlgorithmSigner
  205. }
  206. // NewCertSigner returns a Signer that signs with the given Certificate, whose
  207. // private key is held by signer. It returns an error if the public key in cert
  208. // doesn't match the key used by signer.
  209. func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
  210.     if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
  211.         return nil, errors.New("ssh: signer and cert have different public key")
  212.     }
  213.     if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
  214.         return &algorithmOpenSSHCertSigner{
  215.             &openSSHCertSigner{cert, signer}, algorithmSigner}, nil
  216.     } else {
  217.         return &openSSHCertSigner{cert, signer}, nil
  218.     }
  219. }
  220. func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
  221.     return s.signer.Sign(rand, data)
  222. }
  223. func (s *openSSHCertSigner) PublicKey() PublicKey {
  224.     return s.pub
  225. }
  226. func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
  227.     return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
  228. }
  229. const sourceAddressCriticalOption = "source-address"
  230. // CertChecker does the work of verifying a certificate. Its methods
  231. // can be plugged into ClientConfig.HostKeyCallback and
  232. // ServerConfig.PublicKeyCallback. For the CertChecker to work,
  233. // minimally, the IsAuthority callback should be set.
  234. type CertChecker struct {
  235.     // SupportedCriticalOptions lists the CriticalOptions that the
  236.     // server application layer understands. These are only used
  237.     // for user certificates.
  238.     SupportedCriticalOptions []string
  239.     // IsUserAuthority should return true if the key is recognized as an
  240.     // authority for the given user certificate. This allows for
  241.     // certificates to be signed by other certificates. This must be set
  242.     // if this CertChecker will be checking user certificates.
  243.     IsUserAuthority func(auth PublicKey) bool
  244.     // IsHostAuthority should report whether the key is recognized as
  245.     // an authority for this host. This allows for certificates to be
  246.     // signed by other keys, and for those other keys to only be valid
  247.     // signers for particular hostnames. This must be set if this
  248.     // CertChecker will be checking host certificates.
  249.     IsHostAuthority func(auth PublicKey, address string) bool
  250.     // Clock is used for verifying time stamps. If nil, time.Now
  251.     // is used.
  252.     Clock func() time.Time
  253.     // UserKeyFallback is called when CertChecker.Authenticate encounters a
  254.     // public key that is not a certificate. It must implement validation
  255.     // of user keys or else, if nil, all such keys are rejected.
  256.     UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
  257.     // HostKeyFallback is called when CertChecker.CheckHostKey encounters a
  258.     // public key that is not a certificate. It must implement host key
  259.     // validation or else, if nil, all such keys are rejected.
  260.     HostKeyFallback HostKeyCallback
  261.     // IsRevoked is called for each certificate so that revocation checking
  262.     // can be implemented. It should return true if the given certificate
  263.     // is revoked and false otherwise. If nil, no certificates are
  264.     // considered to have been revoked.
  265.     IsRevoked func(cert *Certificate) bool
  266. }
  267. // CheckHostKey checks a host key certificate. This method can be
  268. // plugged into ClientConfig.HostKeyCallback.
  269. func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
  270.     cert, ok := key.(*Certificate)
  271.     if !ok {
  272.         if c.HostKeyFallback != nil {
  273.             return c.HostKeyFallback(addr, remote, key)
  274.         }
  275.         return errors.New("ssh: non-certificate host key")
  276.     }
  277.     if cert.CertType != HostCert {
  278.         return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
  279.     }
  280.     if !c.IsHostAuthority(cert.SignatureKey, addr) {
  281.         return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
  282.     }
  283.     hostname, _, err := net.SplitHostPort(addr)
  284.     if err != nil {
  285.         return err
  286.     }
  287.     // Pass hostname only as principal for host certificates (consistent with OpenSSH)
  288.     return c.CheckCert(hostname, cert)
  289. }
  290. // Authenticate checks a user certificate. Authenticate can be used as
  291. // a value for ServerConfig.PublicKeyCallback.
  292. func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
  293.     cert, ok := pubKey.(*Certificate)
  294.     if !ok {
  295.         if c.UserKeyFallback != nil {
  296.             return c.UserKeyFallback(conn, pubKey)
  297.         }
  298.         return nil, errors.New("ssh: normal key pairs not accepted")
  299.     }
  300.     if cert.CertType != UserCert {
  301.         return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
  302.     }
  303.     if !c.IsUserAuthority(cert.SignatureKey) {
  304.         return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
  305.     }
  306.     if err := c.CheckCert(conn.User(), cert); err != nil {
  307.         return nil, err
  308.     }
  309.     return &cert.Permissions, nil
  310. }
  311. // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
  312. // the signature of the certificate.
  313. func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
  314.     if c.IsRevoked != nil && c.IsRevoked(cert) {
  315.         return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial)
  316.     }
  317.     for opt := range cert.CriticalOptions {
  318.         // sourceAddressCriticalOption will be enforced by
  319.         // serverAuthenticate
  320.         if opt == sourceAddressCriticalOption {
  321.             continue
  322.         }
  323.         found := false
  324.         for _, supp := range c.SupportedCriticalOptions {
  325.             if supp == opt {
  326.                 found = true
  327.                 break
  328.             }
  329.         }
  330.         if !found {
  331.             return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
  332.         }
  333.     }
  334.     if len(cert.ValidPrincipals) > 0 {
  335.         // By default, certs are valid for all users/hosts.
  336.         found := false
  337.         for _, p := range cert.ValidPrincipals {
  338.             if p == principal {
  339.                 found = true
  340.                 break
  341.             }
  342.         }
  343.         if !found {
  344.             return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
  345.         }
  346.     }
  347.     clock := c.Clock
  348.     if clock == nil {
  349.         clock = time.Now
  350.     }
  351.     unixNow := clock().Unix()
  352.     if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
  353.         return fmt.Errorf("ssh: cert is not yet valid")
  354.     }
  355.     if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
  356.         return fmt.Errorf("ssh: cert has expired")
  357.     }
  358.     if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
  359.         return fmt.Errorf("ssh: certificate signature does not verify")
  360.     }
  361.     return nil
  362. }
  363. // SignCert signs the certificate with an authority, setting the Nonce,
  364. // SignatureKey, and Signature fields.
  365. func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
  366.     c.Nonce = make([]byte, 32)
  367.     if _, err := io.ReadFull(rand, c.Nonce); err != nil {
  368.         return err
  369.     }
  370.     c.SignatureKey = authority.PublicKey()
  371.     sig, err := authority.Sign(rand, c.bytesForSigning())
  372.     if err != nil {
  373.         return err
  374.     }
  375.     c.Signature = sig
  376.     return nil
  377. }
  378. var certAlgoNames = map[string]string{
  379.     KeyAlgoRSA:        CertAlgoRSAv01,
  380.     KeyAlgoDSA:        CertAlgoDSAv01,
  381.     KeyAlgoECDSA256:   CertAlgoECDSA256v01,
  382.     KeyAlgoECDSA384:   CertAlgoECDSA384v01,
  383.     KeyAlgoECDSA521:   CertAlgoECDSA521v01,
  384.     KeyAlgoSKECDSA256: CertAlgoSKECDSA256v01,
  385.     KeyAlgoED25519:    CertAlgoED25519v01,
  386.     KeyAlgoSKED25519:  CertAlgoSKED25519v01,
  387. }
  388. // certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
  389. // Panics if a non-certificate algorithm is passed.
  390. func certToPrivAlgo(algo string) string {
  391.     for privAlgo, pubAlgo := range certAlgoNames {
  392.         if pubAlgo == algo {
  393.             return privAlgo
  394.         }
  395.     }
  396.     panic("unknown cert algorithm")
  397. }
  398. func (cert *Certificate) bytesForSigning() []byte {
  399.     c2 := *cert
  400.     c2.Signature = nil
  401.     out := c2.Marshal()
  402.     // Drop trailing signature length.
  403.     return out[:len(out)-4]
  404. }
  405. // Marshal serializes c into OpenSSH's wire format. It is part of the
  406. // PublicKey interface.
  407. func (c *Certificate) Marshal() []byte {
  408.     generic := genericCertData{
  409.         Serial:          c.Serial,
  410.         CertType:        c.CertType,
  411.         KeyId:           c.KeyId,
  412.         ValidPrincipals: marshalStringList(c.ValidPrincipals),
  413.         ValidAfter:      uint64(c.ValidAfter),
  414.         ValidBefore:     uint64(c.ValidBefore),
  415.         CriticalOptions: marshalTuples(c.CriticalOptions),
  416.         Extensions:      marshalTuples(c.Extensions),
  417.         Reserved:        c.Reserved,
  418.         SignatureKey:    c.SignatureKey.Marshal(),
  419.     }
  420.     if c.Signature != nil {
  421.         generic.Signature = Marshal(c.Signature)
  422.     }
  423.     genericBytes := Marshal(&generic)
  424.     keyBytes := c.Key.Marshal()
  425.     _, keyBytes, _ = parseString(keyBytes)
  426.     prefix := Marshal(&struct {
  427.         Name  string
  428.         Nonce []byte
  429.         Key   []byte `ssh:"rest"`
  430.     }{c.Type(), c.Nonce, keyBytes})
  431.     result := make([]byte, 0, len(prefix)+len(genericBytes))
  432.     result = append(result, prefix...)
  433.     result = append(result, genericBytes...)
  434.     return result
  435. }
  436. // Type returns the key name. It is part of the PublicKey interface.
  437. func (c *Certificate) Type() string {
  438.     algo, ok := certAlgoNames[c.Key.Type()]
  439.     if !ok {
  440.         panic("unknown cert key type " + c.Key.Type())
  441.     }
  442.     return algo
  443. }
  444. // Verify verifies a signature against the certificate's public
  445. // key. It is part of the PublicKey interface.
  446. func (c *Certificate) Verify(data []byte, sig *Signature) error {
  447.     return c.Key.Verify(data, sig)
  448. }
  449. func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
  450.     format, in, ok := parseString(in)
  451.     if !ok {
  452.         return
  453.     }
  454.     out = &Signature{
  455.         Format: string(format),
  456.     }
  457.     if out.Blob, in, ok = parseString(in); !ok {
  458.         return
  459.     }
  460.     switch out.Format {
  461.     case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01:
  462.         out.Rest = in
  463.         return out, nil, ok
  464.     }
  465.     return out, in, ok
  466. }
  467. func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
  468.     sigBytes, rest, ok := parseString(in)
  469.     if !ok {
  470.         return
  471.     }
  472.     out, trailing, ok := parseSignatureBody(sigBytes)
  473.     if !ok || len(trailing) > 0 {
  474.         return nil, nil, false
  475.     }
  476.     return
  477. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×