github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/go.crypto/ssh/common.go (about)

     1  // Copyright 2011 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  
     5  package ssh
     6  
     7  import (
     8  	"crypto/dsa"
     9  	"crypto/rsa"
    10  	"math/big"
    11  	"strconv"
    12  	"sync"
    13  )
    14  
    15  // These are string constants in the SSH protocol.
    16  const (
    17  	kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
    18  	hostAlgoRSA     = "ssh-rsa"
    19  	macSHA196       = "hmac-sha1-96"
    20  	compressionNone = "none"
    21  	serviceUserAuth = "ssh-userauth"
    22  	serviceSSH      = "ssh-connection"
    23  )
    24  
    25  var supportedKexAlgos = []string{kexAlgoDH14SHA1}
    26  var supportedHostKeyAlgos = []string{hostAlgoRSA}
    27  var supportedMACs = []string{macSHA196}
    28  var supportedCompressions = []string{compressionNone}
    29  
    30  // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
    31  type dhGroup struct {
    32  	g, p *big.Int
    33  }
    34  
    35  // dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
    36  // Oakley Group 14 in RFC 3526.
    37  var dhGroup14 *dhGroup
    38  
    39  var dhGroup14Once sync.Once
    40  
    41  func initDHGroup14() {
    42  	p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
    43  
    44  	dhGroup14 = &dhGroup{
    45  		g: new(big.Int).SetInt64(2),
    46  		p: p,
    47  	}
    48  }
    49  
    50  // UnexpectedMessageError results when the SSH message that we received didn't
    51  // match what we wanted.
    52  type UnexpectedMessageError struct {
    53  	expected, got uint8
    54  }
    55  
    56  func (u UnexpectedMessageError) Error() string {
    57  	return "ssh: unexpected message type " + strconv.Itoa(int(u.got)) + " (expected " + strconv.Itoa(int(u.expected)) + ")"
    58  }
    59  
    60  // ParseError results from a malformed SSH message.
    61  type ParseError struct {
    62  	msgType uint8
    63  }
    64  
    65  func (p ParseError) Error() string {
    66  	return "ssh: parse error in message type " + strconv.Itoa(int(p.msgType))
    67  }
    68  
    69  type handshakeMagics struct {
    70  	clientVersion, serverVersion []byte
    71  	clientKexInit, serverKexInit []byte
    72  }
    73  
    74  func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
    75  	for _, clientAlgo := range clientAlgos {
    76  		for _, serverAlgo := range serverAlgos {
    77  			if clientAlgo == serverAlgo {
    78  				return clientAlgo, true
    79  			}
    80  		}
    81  	}
    82  
    83  	return
    84  }
    85  
    86  func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
    87  	kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
    88  	if !ok {
    89  		return
    90  	}
    91  
    92  	hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
    93  	if !ok {
    94  		return
    95  	}
    96  
    97  	transport.writer.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
    98  	if !ok {
    99  		return
   100  	}
   101  
   102  	transport.reader.cipherAlgo, ok = findCommonAlgorithm(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
   103  	if !ok {
   104  		return
   105  	}
   106  
   107  	transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
   108  	if !ok {
   109  		return
   110  	}
   111  
   112  	transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
   113  	if !ok {
   114  		return
   115  	}
   116  
   117  	transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
   118  	if !ok {
   119  		return
   120  	}
   121  
   122  	transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
   123  	if !ok {
   124  		return
   125  	}
   126  
   127  	ok = true
   128  	return
   129  }
   130  
   131  // Cryptographic configuration common to both ServerConfig and ClientConfig.
   132  type CryptoConfig struct {
   133  	// The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
   134  	// used.
   135  	Ciphers []string
   136  }
   137  
   138  func (c *CryptoConfig) ciphers() []string {
   139  	if c.Ciphers == nil {
   140  		return DefaultCipherOrder
   141  	}
   142  	return c.Ciphers
   143  }
   144  
   145  // serialize a signed slice according to RFC 4254 6.6.
   146  func serializeSignature(algoname string, sig []byte) []byte {
   147  	length := stringLength([]byte(algoname))
   148  	length += stringLength(sig)
   149  
   150  	ret := make([]byte, length)
   151  	r := marshalString(ret, []byte(algoname))
   152  	r = marshalString(r, sig)
   153  
   154  	return ret
   155  }
   156  
   157  // serialize an rsa.PublicKey or dsa.PublicKey according to RFC 4253 6.6.
   158  func serializePublickey(key interface{}) []byte {
   159  	algoname := algoName(key)
   160  	switch key := key.(type) {
   161  	case rsa.PublicKey:
   162  		e := new(big.Int).SetInt64(int64(key.E))
   163  		length := stringLength([]byte(algoname))
   164  		length += intLength(e)
   165  		length += intLength(key.N)
   166  		ret := make([]byte, length)
   167  		r := marshalString(ret, []byte(algoname))
   168  		r = marshalInt(r, e)
   169  		marshalInt(r, key.N)
   170  		return ret
   171  	case dsa.PublicKey:
   172  		length := stringLength([]byte(algoname))
   173  		length += intLength(key.P)
   174  		length += intLength(key.Q)
   175  		length += intLength(key.G)
   176  		length += intLength(key.Y)
   177  		ret := make([]byte, length)
   178  		r := marshalString(ret, []byte(algoname))
   179  		r = marshalInt(r, key.P)
   180  		r = marshalInt(r, key.Q)
   181  		r = marshalInt(r, key.G)
   182  		marshalInt(r, key.Y)
   183  		return ret
   184  	}
   185  	panic("unexpected key type")
   186  }
   187  
   188  func algoName(key interface{}) string {
   189  	switch key.(type) {
   190  	case rsa.PublicKey:
   191  		return "ssh-rsa"
   192  	case dsa.PublicKey:
   193  		return "ssh-dss"
   194  	}
   195  	panic("unexpected key type")
   196  }
   197  
   198  // buildDataSignedForAuth returns the data that is signed in order to prove
   199  // posession of a private key. See RFC 4252, section 7.
   200  func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
   201  	user := []byte(req.User)
   202  	service := []byte(req.Service)
   203  	method := []byte(req.Method)
   204  
   205  	length := stringLength(sessionId)
   206  	length += 1
   207  	length += stringLength(user)
   208  	length += stringLength(service)
   209  	length += stringLength(method)
   210  	length += 1
   211  	length += stringLength(algo)
   212  	length += stringLength(pubKey)
   213  
   214  	ret := make([]byte, length)
   215  	r := marshalString(ret, sessionId)
   216  	r[0] = msgUserAuthRequest
   217  	r = r[1:]
   218  	r = marshalString(r, user)
   219  	r = marshalString(r, service)
   220  	r = marshalString(r, method)
   221  	r[0] = 1
   222  	r = r[1:]
   223  	r = marshalString(r, algo)
   224  	r = marshalString(r, pubKey)
   225  	return ret
   226  }
   227  
   228  // safeString sanitises s according to RFC 4251, section 9.2. 
   229  // All control characters except tab, carriage return and newline are
   230  // replaced by 0x20.
   231  func safeString(s string) string {
   232  	out := []byte(s)
   233  	for i, c := range out {
   234  		if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
   235  			out[i] = 0x20
   236  		}
   237  	}
   238  	return string(out)
   239  }