Develop and Download Open Source Software

Browse Subversion Repository

Diff of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ssh.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4303 by maya, Mon Feb 14 03:25:46 2011 UTC revision 4304 by maya, Mon Feb 14 09:09:07 2011 UTC
# Line 31  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI Line 31  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
31  #include "util.h"  #include "util.h"
32  #include "resource.h"  #include "resource.h"
33  #include "libputty.h"  #include "libputty.h"
34    #include "key.h"
35    
36  #include <openssl/bn.h>  #include <openssl/bn.h>
37  #include <openssl/evp.h>  #include <openssl/evp.h>
# Line 50  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI Line 51  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
51  #include "crypt.h"  #include "crypt.h"
52  #include "fwd.h"  #include "fwd.h"
53  #include "sftp.h"  #include "sftp.h"
54    #include "kex.h"
55    
56  #include <sys/types.h>  #include <sys/types.h>
57  #include <sys/stat.h>  #include <sys/stat.h>
# Line 65  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI Line 67  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
67    
68  //#define DONT_WANTCONFIRM 1  // (2005.3.28 yutaka)  //#define DONT_WANTCONFIRM 1  // (2005.3.28 yutaka)
69  #undef DONT_WANTCONFIRM // (2008.11.25 maya)  #undef DONT_WANTCONFIRM // (2008.11.25 maya)
 #define INTBLOB_LEN 20  
 #define SIGBLOB_LEN (2*INTBLOB_LEN)  
70    
71  //  //
72  // SSH2 data structure  // SSH2 data structure
# Line 3950  void debug_print(int no, char *msg, int Line 3950  void debug_print(int no, char *msg, int
3950  #endif  #endif
3951  }  }
3952    
3953  static Newkeys current_keys[MODE_MAX];  Newkeys current_keys[MODE_MAX];
3954    
3955    
3956  #define write_buffer_file(buf,len) do_write_buffer_file(buf,len,__FILE__,__LINE__)  #define write_buffer_file(buf,len) do_write_buffer_file(buf,len,__FILE__,__LINE__)
# Line 4699  error:; Line 4699  error:;
4699  }  }
4700    
4701    
   
 static DH *dh_new_group_asc(const char *gen, const char *modulus)  
 {  
         DH *dh = NULL;  
   
         if ((dh = DH_new()) == NULL) {  
                 printf("dh_new_group_asc: DH_new");  
                 goto error;  
         }  
   
         // PとGは公開してもよい素数の組み合わせ  
         if (BN_hex2bn(&dh->p, modulus) == 0) {  
                 printf("BN_hex2bn p");  
                 goto error;  
         }  
   
         if (BN_hex2bn(&dh->g, gen) == 0) {  
                 printf("BN_hex2bn g");  
                 goto error;  
         }  
   
         return (dh);  
   
 error:  
         DH_free(dh);  
         return (NULL);  
 }  
   
   
 static DH *dh_new_group1(void)  
 {  
         static char *gen = "2", *group1 =  
             "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"  
             "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"  
             "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"  
             "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"  
             "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"  
             "FFFFFFFF" "FFFFFFFF";  
   
         return (dh_new_group_asc(gen, group1));  
 }  
   
   
 static DH *dh_new_group14(void)  
 {  
     static char *gen = "2", *group14 =  
         "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"  
         "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"  
         "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"  
         "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"  
         "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"  
         "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"  
         "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"  
         "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"  
         "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"  
         "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"  
         "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";  
   
         return (dh_new_group_asc(gen, group14));  
 }  
   
   
 // DH鍵を生成する  
 static void dh_gen_key(PTInstVar pvar, DH *dh, int we_need /* bytes */ )  
 {  
         int i;  
   
         dh->priv_key = NULL;  
   
         // 秘密にすべき乱数(X)を生成  
         for (i = 0 ; i < 10 ; i++) { // retry counter  
                 if (dh->priv_key != NULL) {  
                         BN_clear_free(dh->priv_key);  
                 }  
                 dh->priv_key = BN_new();  
                 if (dh->priv_key == NULL)  
                         goto error;  
                 if (BN_rand(dh->priv_key, 2*(we_need*8), 0, 0) == 0)  
                         goto error;  
                 if (DH_generate_key(dh) == 0)  
                         goto error;  
                 if (dh_pub_is_valid(dh, dh->pub_key))  
                         break;  
         }  
         if (i >= 10) {  
                 goto error;  
         }  
         return;  
   
 error:;  
         notify_fatal_error(pvar, "error occurred @ dh_gen_key()");  
   
 }  
   
4702  //  //
4703  // KEX_DH_GRP1_SHA1 or KEX_DH_GRP14_SHA1  // KEX_DH_GRP1_SHA1 or KEX_DH_GRP14_SHA1
4704  //  //
# Line 4853  error:; Line 4759  error:;
4759    
4760    
4761  //  //
4762  // KEX_DH_GEX_SHA1  // KEX_DH_GEX_SHA1 or KEX_DH_GEX_SHA256
4763  //  //
4764  // cf.  Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol  // cf.  Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol
4765  //      (draft-ietf-secsh-dh-group-exchange-04.txt)  //      (draft-ietf-secsh-dh-group-exchange-04.txt)
4766  //  //
4767    
 static int dh_estimate(int bits)  
 {  
         if (bits <= 128)  
                 return (1024);  /* O(2**86) */  
         if (bits <= 192)  
                 return (2048);  /* O(2**116) */  
         return (4096);      /* O(2**156) */  
 }  
   
4768  static void SSH2_dh_gex_kex_init(PTInstVar pvar)  static void SSH2_dh_gex_kex_init(PTInstVar pvar)
4769  {  {
4770          buffer_t *msg = NULL;          buffer_t *msg = NULL;
# Line 5000  error:; Line 4897  error:;
4897  }  }
4898    
4899    
   
 // SHA-1(160bit)を求める  
 unsigned char *kex_dh_hash(char *client_version_string,  
                            char *server_version_string,  
                            char *ckexinit, int ckexinitlen,  
                            char *skexinit, int skexinitlen,  
                            u_char *serverhostkeyblob, int sbloblen,  
                            BIGNUM *client_dh_pub,  
                            BIGNUM *server_dh_pub,  
                            BIGNUM *shared_secret)  
 {  
         buffer_t *b;  
         static unsigned char digest[EVP_MAX_MD_SIZE];  
         const EVP_MD *evp_md = EVP_sha1();  
         EVP_MD_CTX md;  
   
         b = buffer_init();  
         buffer_put_string(b, client_version_string, strlen(client_version_string));  
         buffer_put_string(b, server_version_string, strlen(server_version_string));  
   
         /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */  
         buffer_put_int(b, ckexinitlen+1);  
         buffer_put_char(b, SSH2_MSG_KEXINIT);  
         buffer_append(b, ckexinit, ckexinitlen);  
         buffer_put_int(b, skexinitlen+1);  
         buffer_put_char(b, SSH2_MSG_KEXINIT);  
         buffer_append(b, skexinit, skexinitlen);  
   
         buffer_put_string(b, serverhostkeyblob, sbloblen);  
         buffer_put_bignum2(b, client_dh_pub);  
         buffer_put_bignum2(b, server_dh_pub);  
         buffer_put_bignum2(b, shared_secret);  
   
         // yutaka  
         //debug_print(38, buffer_ptr(b), buffer_len(b));  
   
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, buffer_ptr(b), buffer_len(b));  
         EVP_DigestFinal(&md, digest, NULL);  
   
         buffer_free(b);  
   
         //write_buffer_file(digest, EVP_MD_size(evp_md));  
   
         return digest;  
 }  
   
   
 int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)  
 {  
         int i;  
         int n = BN_num_bits(dh_pub);  
         int bits_set = 0;  
   
         if (dh_pub->neg) {  
                 //logit("invalid public DH value: negativ");  
                 return 0;  
         }  
         for (i = 0; i <= n; i++)  
                 if (BN_is_bit_set(dh_pub, i))  
                         bits_set++;  
         //debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));  
   
         /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */  
         if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))  
                 return 1;  
         //logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));  
         return 0;  
 }  
   
   
 static u_char *derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret,  
                           char *session_id, int session_id_len,  
                           enum kex_algorithm kex_type)  
 {  
         buffer_t *b;  
         const EVP_MD *evp_md = ssh2_kex_algorithms[kex_type].evp_md();  
         EVP_MD_CTX md;  
         char c = id;  
         int have;  
         int mdsz = EVP_MD_size(evp_md);  
         u_char *digest = malloc(roundup(need, mdsz));  
   
         if (digest == NULL)  
                 goto skip;  
   
         b = buffer_init();  
         if (b == NULL)  
                 goto skip;  
   
         buffer_put_bignum2(b, shared_secret);  
   
         /* K1 = HASH(K || H || "A" || session_id) */  
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, buffer_ptr(b), buffer_len(b));  
         EVP_DigestUpdate(&md, hash, mdsz);  
         EVP_DigestUpdate(&md, &c, 1);  
         EVP_DigestUpdate(&md, session_id, session_id_len);  
         EVP_DigestFinal(&md, digest, NULL);  
   
         /*  
          * expand key:  
          * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)  
          * Key = K1 || K2 || ... || Kn  
          */  
         for (have = mdsz; need > have; have += mdsz) {  
                 EVP_DigestInit(&md, evp_md);  
                 EVP_DigestUpdate(&md, buffer_ptr(b), buffer_len(b));  
                 EVP_DigestUpdate(&md, hash, mdsz);  
                 EVP_DigestUpdate(&md, digest, have);  
                 EVP_DigestFinal(&md, digest + have, NULL);  
         }  
         buffer_free(b);  
   
 skip:;  
         return digest;  
 }  
   
   
4900  static void ssh2_set_newkeys(PTInstVar pvar, int mode)  static void ssh2_set_newkeys(PTInstVar pvar, int mode)
4901  {  {
4902  #if 1  #if 1
# Line 5138  static void ssh2_set_newkeys(PTInstVar p Line 4916  static void ssh2_set_newkeys(PTInstVar p
4916  }  }
4917    
4918    
 void kex_derive_keys(PTInstVar pvar, int need, u_char *hash, BIGNUM *shared_secret,  
                      char *session_id, int session_id_len)  
 {  
 #define NKEYS   6  
         u_char *keys[NKEYS];  
         int i, mode, ctos;  
   
         for (i = 0; i < NKEYS; i++) {  
                 keys[i] = derive_key('A'+i, need, hash, shared_secret, session_id, session_id_len, pvar->kex_type);  
                 //debug_print(i, keys[i], need);  
         }  
   
         for (mode = 0; mode < MODE_MAX; mode++) {  
                 if (mode == MODE_OUT)  
                         ctos = 1;  
                 else  
                         ctos = 0;  
   
 #if 0  
                 // free already allocated buffer (2004.12.27 yutaka)  
                 // キー再作成時にMAC corruptとなるので削除。(2005.1.5 yutaka)  
                 if (current_keys[mode].enc.iv != NULL)  
                         free(current_keys[mode].enc.iv);  
                 if (current_keys[mode].enc.key != NULL)  
                         free(current_keys[mode].enc.key);  
                 if (current_keys[mode].mac.key != NULL)  
                         free(current_keys[mode].mac.key);  
 #endif  
   
                 // setting  
                 current_keys[mode].enc.iv  = keys[ctos ? 0 : 1];  
                 current_keys[mode].enc.key = keys[ctos ? 2 : 3];  
                 current_keys[mode].mac.key = keys[ctos ? 4 : 5];  
   
                 //debug_print(20 + mode*3, current_keys[mode]->enc.iv, 8);  
                 //debug_print(21 + mode*3, current_keys[mode]->enc.key, 24);  
                 //debug_print(22 + mode*3, current_keys[mode]->mac.key, 24);  
         }  
 }  
   
   
 //////////////////////////////////////////////////////////////////////////////  
 //  
 // Key verify function  
 //  
 //////////////////////////////////////////////////////////////////////////////  
   
 //  
 // DSS  
 //  
   
 static int ssh_dss_verify(DSA *key,  
                           u_char *signature, u_int signaturelen,  
                           u_char *data, u_int datalen)  
 {  
         DSA_SIG *sig;  
         const EVP_MD *evp_md = EVP_sha1();  
         EVP_MD_CTX md;  
         unsigned char digest[EVP_MAX_MD_SIZE], *sigblob;  
         unsigned int len, dlen;  
         int ret;  
         char *ptr;  
   
         OpenSSL_add_all_digests();  
   
         if (key == NULL) {  
                 return -2;  
         }  
   
         ptr = signature;  
   
         // step1  
         if (signaturelen == 0x28) {  
                 // workaround for SSH-2.0-2.0* and SSH-2.0-2.1* (2006.11.18 maya)  
                 ptr -= 4;  
         }  
         else {  
                 len = get_uint32_MSBfirst(ptr);  
                 ptr += 4;  
                 if (strncmp("ssh-dss", ptr, len) != 0) {  
                         return -3;  
                 }  
                 ptr += len;  
         }  
   
         // step2  
         len = get_uint32_MSBfirst(ptr);  
         ptr += 4;  
         sigblob = ptr;  
         ptr += len;  
   
         if (len != SIGBLOB_LEN) {  
                 return -4;  
         }  
   
         /* parse signature */  
         if ((sig = DSA_SIG_new()) == NULL)  
                 return -5;  
         if ((sig->r = BN_new()) == NULL)  
                 return -6;  
         if ((sig->s = BN_new()) == NULL)  
                 return -7;  
         BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);  
         BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);  
   
         /* sha1 the data */  
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, data, datalen);  
         EVP_DigestFinal(&md, digest, &dlen);  
   
         ret = DSA_do_verify(digest, dlen, sig, key);  
         memset(digest, 'd', sizeof(digest));  
   
         DSA_SIG_free(sig);  
   
         return ret;  
 }  
   
   
 //  
 // RSA  
 //  
   
 /*  
 * See:  
 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/  
 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn  
 */  
 /*  
 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)  
 *       oiw(14) secsig(3) algorithms(2) 26 }  
 */  
 static const u_char id_sha1[] = {  
         0x30, 0x21, /* type Sequence, length 0x21 (33) */  
                 0x30, 0x09, /* type Sequence, length 0x09 */  
                 0x06, 0x05, /* type OID, length 0x05 */  
                 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */  
                 0x05, 0x00, /* NULL */  
                 0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */  
 };  
 /*  
 * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)  
 *       rsadsi(113549) digestAlgorithm(2) 5 }  
 */  
 static const u_char id_md5[] = {  
         0x30, 0x20, /* type Sequence, length 0x20 (32) */  
                 0x30, 0x0c, /* type Sequence, length 0x09 */  
                 0x06, 0x08, /* type OID, length 0x05 */  
                 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */  
                 0x05, 0x00, /* NULL */  
                 0x04, 0x10  /* Octet string, length 0x10 (16), followed by md5 hash */  
 };  
   
 static int openssh_RSA_verify(int type, u_char *hash, u_int hashlen,  
                               u_char *sigbuf, u_int siglen, RSA *rsa)  
 {  
         u_int ret, rsasize, oidlen = 0, hlen = 0;  
         int len;  
         const u_char *oid = NULL;  
         u_char *decrypted = NULL;  
   
         ret = 0;  
         switch (type) {  
         case NID_sha1:  
                 oid = id_sha1;  
                 oidlen = sizeof(id_sha1);  
                 hlen = 20;  
                 break;  
         case NID_md5:  
                 oid = id_md5;  
                 oidlen = sizeof(id_md5);  
                 hlen = 16;  
                 break;  
         default:  
                 goto done;  
                 break;  
         }  
         if (hashlen != hlen) {  
                 //error("bad hashlen");  
                 goto done;  
         }  
         rsasize = RSA_size(rsa);  
         if (siglen == 0 || siglen > rsasize) {  
                 //error("bad siglen");  
                 goto done;  
         }  
         decrypted = malloc(rsasize);  
         if (decrypted == NULL)  
                 return 1; // error  
   
         if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,  
                                       RSA_PKCS1_PADDING)) < 0) {  
                         //error("RSA_public_decrypt failed: %s",  
                         //    ERR_error_string(ERR_get_error(), NULL));  
                         goto done;  
                 }  
                 if (len != hlen + oidlen) {  
                         //error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);  
                         goto done;  
                 }  
                 if (memcmp(decrypted, oid, oidlen) != 0) {  
                         //error("oid mismatch");  
                         goto done;  
                 }  
                 if (memcmp(decrypted + oidlen, hash, hlen) != 0) {  
                         //error("hash mismatch");  
                         goto done;  
                 }  
                 ret = 1;  
 done:  
                 if (decrypted)  
                         free(decrypted);  
                 return ret;  
 }  
   
 static int ssh_rsa_verify(RSA *key,  
                           u_char *signature, u_int signaturelen,  
                           u_char *data, u_int datalen)  
 {  
         const EVP_MD *evp_md;  
         EVP_MD_CTX md;  
         //      char *ktype;  
         u_char digest[EVP_MAX_MD_SIZE], *sigblob;  
         u_int len, dlen, modlen;  
 //      int rlen, ret, nid;  
         int ret, nid;  
         char *ptr;  
   
         OpenSSL_add_all_digests();  
   
         if (key == NULL) {  
                 return -2;  
         }  
         if (BN_num_bits(key->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {  
                 return -3;  
         }  
         //debug_print(41, signature, signaturelen);  
         ptr = signature;  
   
         // step1  
         len = get_uint32_MSBfirst(ptr);  
         ptr += 4;  
         if (strncmp("ssh-rsa", ptr, len) != 0) {  
                 return -4;  
         }  
         ptr += len;  
   
         // step2  
         len = get_uint32_MSBfirst(ptr);  
         ptr += 4;  
         sigblob = ptr;  
         ptr += len;  
 #if 0  
         rlen = get_uint32_MSBfirst(ptr);  
         if (rlen != 0) {  
                 return -1;  
         }  
 #endif  
   
         /* RSA_verify expects a signature of RSA_size */  
         modlen = RSA_size(key);  
         if (len > modlen) {  
                 return -5;  
   
         } else if (len < modlen) {  
                 u_int diff = modlen - len;  
                 sigblob = realloc(sigblob, modlen);  
                 memmove(sigblob + diff, sigblob, len);  
                 memset(sigblob, 0, diff);  
                 len = modlen;  
         }  
           
         /* sha1 the data */  
         //      nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;  
         nid = NID_sha1;  
         if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {  
                 //error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);  
                 return -6;  
         }  
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, data, datalen);  
         EVP_DigestFinal(&md, digest, &dlen);  
   
         ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key);  
   
         memset(digest, 'd', sizeof(digest));  
         memset(sigblob, 's', len);  
         //free(sigblob);  
         //debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");  
   
         return ret;  
 }  
   
 static int key_verify(RSA *rsa_key, DSA *dsa_key,  
                       unsigned char *signature, unsigned int signaturelen,  
                       unsigned char *data, unsigned int datalen)  
 {  
         int ret = 0;  
   
         if (rsa_key != NULL) {  
                 ret = ssh_rsa_verify(rsa_key, signature, signaturelen, data, datalen);  
   
         } else if (dsa_key != NULL) {  
                 ret = ssh_dss_verify(dsa_key, signature, signaturelen, data, datalen);  
   
         } else {  
                 return -1;  
         }  
   
         return (ret);   // success  
 }  
   
 //  
 // RSA構造体の複製  
 //  
 RSA *duplicate_RSA(RSA *src)  
 {  
         RSA *rsa = NULL;  
   
         rsa = RSA_new();  
         if (rsa == NULL)  
                 goto error;  
         rsa->n = BN_new();  
         rsa->e = BN_new();  
         if (rsa->n == NULL || rsa->e == NULL) {  
                 RSA_free(rsa);  
                 goto error;  
         }  
   
         // 深いコピー(deep copy)を行う。浅いコピー(shallow copy)はNG。  
         BN_copy(rsa->n, src->n);  
         BN_copy(rsa->e, src->e);  
   
 error:  
         return (rsa);  
 }  
   
   
 //  
 // DSA構造体の複製  
 //  
 DSA *duplicate_DSA(DSA *src)  
 {  
         DSA *dsa = NULL;  
   
         dsa = DSA_new();  
         if (dsa == NULL)  
                 goto error;  
         dsa->p = BN_new();  
         dsa->q = BN_new();  
         dsa->g = BN_new();  
         dsa->pub_key = BN_new();  
         if (dsa->p == NULL ||  
             dsa->q == NULL ||  
             dsa->g == NULL ||  
             dsa->pub_key == NULL) {  
                 DSA_free(dsa);  
                 goto error;  
         }  
   
         // 深いコピー(deep copy)を行う。浅いコピー(shallow copy)はNG。  
         BN_copy(dsa->p, src->p);  
         BN_copy(dsa->q, src->q);  
         BN_copy(dsa->g, src->g);  
         BN_copy(dsa->pub_key, src->pub_key);  
   
 error:  
         return (dsa);  
 }  
   
   
 static char* key_fingerprint_raw(Key *k, int *dgst_raw_length)  
 {  
         const EVP_MD *md = NULL;  
         EVP_MD_CTX ctx;  
         char *blob = NULL;  
         char *retval = NULL;  
         int len = 0;  
         int nlen, elen;  
         RSA *rsa;  
   
         *dgst_raw_length = 0;  
   
         // MD5アルゴリズムを使用する  
         md = EVP_md5();  
   
         switch (k->type) {  
         case KEY_RSA1:  
                 rsa = make_key(NULL, k->bits, k->exp, k->mod);  
                 nlen = BN_num_bytes(rsa->n);  
                 elen = BN_num_bytes(rsa->e);  
                 len = nlen + elen;  
                 blob = malloc(len);  
                 if (blob == NULL) {  
                         // TODO:  
                 }  
                 BN_bn2bin(rsa->n, blob);  
                 BN_bn2bin(rsa->e, blob + nlen);  
                 RSA_free(rsa);  
                 break;  
   
         case KEY_DSA:  
         case KEY_RSA:  
                 key_to_blob(k, &blob, &len);  
                 break;  
   
         case KEY_UNSPEC:  
                 return retval;  
                 break;  
   
         default:  
                 //fatal("key_fingerprint_raw: bad key type %d", k->type);  
                 break;  
         }  
   
         if (blob != NULL) {  
                 retval = malloc(EVP_MAX_MD_SIZE);  
                 if (retval == NULL) {  
                         // TODO:  
                 }  
                 EVP_DigestInit(&ctx, md);  
                 EVP_DigestUpdate(&ctx, blob, len);  
                 EVP_DigestFinal(&ctx, retval, dgst_raw_length);  
                 memset(blob, 0, len);  
                 free(blob);  
         } else {  
                 //fatal("key_fingerprint_raw: blob is null");  
         }  
         return retval;  
 }  
   
   
 const char *  
 key_type(const Key *k)  
 {  
         switch (k->type) {  
         case KEY_RSA1:  
                 return "RSA1";  
         case KEY_RSA:  
                 return "RSA";  
         case KEY_DSA:  
                 return "DSA";  
         }  
         return "unknown";  
 }  
   
 unsigned int  
 key_size(const Key *k)  
 {  
         switch (k->type) {  
         case KEY_RSA1:  
                 // SSH1の場合は key->rsa と key->dsa は NULL であるので、使わない。  
                 return k->bits;  
         case KEY_RSA:  
                 return BN_num_bits(k->rsa->n);  
         case KEY_DSA:  
                 return BN_num_bits(k->dsa->p);  
         }  
         return 0;  
 }  
   
 // based on OpenSSH 5.1  
 #define FLDBASE         8  
 #define FLDSIZE_Y       (FLDBASE + 1)  
 #define FLDSIZE_X       (FLDBASE * 2 + 1)  
 static char *  
 key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)  
 {  
         /*  
          * Chars to be used after each other every time the worm  
          * intersects with itself.  Matter of taste.  
          */  
         char    *augmentation_string = " .o+=*BOX@%&#/^SE";  
         char    *retval, *p;  
         unsigned char    field[FLDSIZE_X][FLDSIZE_Y];  
         unsigned int     i, b;  
         int      x, y;  
         size_t   len = strlen(augmentation_string) - 1;  
   
         retval = calloc(1, (FLDSIZE_X + 3 + 1) * (FLDSIZE_Y + 2));  
   
         /* initialize field */  
         memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));  
         x = FLDSIZE_X / 2;  
         y = FLDSIZE_Y / 2;  
   
         /* process raw key */  
         for (i = 0; i < dgst_raw_len; i++) {  
                 int input;  
                 /* each byte conveys four 2-bit move commands */  
                 input = dgst_raw[i];  
                 for (b = 0; b < 4; b++) {  
                         /* evaluate 2 bit, rest is shifted later */  
                         x += (input & 0x1) ? 1 : -1;  
                         y += (input & 0x2) ? 1 : -1;  
   
                         /* assure we are still in bounds */  
                         x = max(x, 0);  
                         y = max(y, 0);  
                         x = min(x, FLDSIZE_X - 1);  
                         y = min(y, FLDSIZE_Y - 1);  
   
                         /* augment the field */  
                         field[x][y]++;  
                         input = input >> 2;  
                 }  
         }  
   
         /* mark starting point and end point*/  
         field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;  
         field[x][y] = len;  
   
         /* fill in retval */  
         _snprintf_s(retval, FLDSIZE_X, _TRUNCATE, "+--[%4s %4u]", key_type(k), key_size(k));  
         p = strchr(retval, '\0');  
   
         /* output upper border */  
         for (i = p - retval - 1; i < FLDSIZE_X; i++)  
                 *p++ = '-';  
         *p++ = '+';  
         *p++ = '\r';  
         *p++ = '\n';  
   
         /* output content */  
         for (y = 0; y < FLDSIZE_Y; y++) {  
                 *p++ = '|';  
                 for (x = 0; x < FLDSIZE_X; x++)  
                         *p++ = augmentation_string[min(field[x][y], len)];  
                 *p++ = '|';  
                 *p++ = '\r';  
                 *p++ = '\n';  
         }  
   
         /* output lower border */  
         *p++ = '+';  
         for (i = 0; i < FLDSIZE_X; i++)  
                 *p++ = '-';  
         *p++ = '+';  
   
         return retval;  
 }  
 #undef  FLDBASE  
 #undef  FLDSIZE_Y  
 #undef  FLDSIZE_X  
   
 //  
 // fingerprint(指紋:ホスト公開鍵のハッシュ)を生成する  
 //  
 char *key_fingerprint(Key *key, enum fp_rep dgst_rep)  
 {  
         char *retval = NULL;  
         unsigned char *dgst_raw;  
         int dgst_raw_len;  
         int i, retval_len;  
   
         // fingerprintのハッシュ値(バイナリ)を求める  
         dgst_raw = key_fingerprint_raw(key, &dgst_raw_len);  
   
         if (dgst_rep == SSH_FP_HEX) {  
                 // 16進表記へ変換する  
                 retval_len = dgst_raw_len * 3 + 1;  
                 retval = malloc(retval_len);  
                 retval[0] = '\0';  
                 for (i = 0; i < dgst_raw_len; i++) {  
                         char hex[4];  
                         _snprintf_s(hex, sizeof(hex), _TRUNCATE, "%02x:", dgst_raw[i]);  
                         strncat_s(retval, retval_len, hex, _TRUNCATE);  
                 }  
   
                 /* Remove the trailing ':' character */  
                 retval[(dgst_raw_len * 3) - 1] = '\0';  
   
         } else if (dgst_rep == SSH_FP_RANDOMART) {  
                 retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, key);  
   
         } else {  
   
         }  
   
         memset(dgst_raw, 0, dgst_raw_len);  
         free(dgst_raw);  
   
         return (retval);  
 }  
   
   
 //  
 // キーのメモリ領域解放  
 //  
 void key_free(Key *key)  
 {  
         switch (key->type) {  
                 case KEY_RSA1:  
                 case KEY_RSA:  
                         if (key->rsa != NULL)  
                                 RSA_free(key->rsa);  
                         key->rsa = NULL;  
                         break;  
   
                 case KEY_DSA:  
                         if (key->dsa != NULL)  
                                 DSA_free(key->dsa);  
                         key->dsa = NULL;  
                         break;  
         }  
         free(key);  
 }  
   
 //  
 // キーから文字列を返却する  
 //  
 char *get_sshname_from_key(Key *key)  
 {  
         if (key->type == KEY_RSA) {  
                 return "ssh-rsa";  
         } else if (key->type == KEY_DSA) {  
                 return "ssh-dss";  
         } else {  
                 return "ssh-unknown";  
         }  
 }  
   
   
 //  
 // キー文字列から種別を判定する  
 //  
 enum hostkey_type get_keytype_from_name(char *name)  
 {  
         if (strcmp(name, "rsa1") == 0) {  
                 return KEY_RSA1;  
         } else if (strcmp(name, "rsa") == 0) {  
                 return KEY_RSA;  
         } else if (strcmp(name, "dsa") == 0) {  
                 return KEY_DSA;  
         } else if (strcmp(name, "ssh-rsa") == 0) {  
                 return KEY_RSA;  
         } else if (strcmp(name, "ssh-dss") == 0) {  
                 return KEY_DSA;  
         }  
         return KEY_UNSPEC;  
 }  
   
   
 //  
 // キー情報からバッファへ変換する (for SSH2)  
 // NOTE:  
 //  
 int key_to_blob(Key *key, char **blobp, int *lenp)  
 {  
         buffer_t *b;  
         char *sshname;  
         int len;  
         int ret = 1;  // success  
   
         b = buffer_init();  
         sshname = get_sshname_from_key(key);  
   
         if (key->type == KEY_RSA) {  
                 buffer_put_string(b, sshname, strlen(sshname));  
                 buffer_put_bignum2(b, key->rsa->e);  
                 buffer_put_bignum2(b, key->rsa->n);  
   
         } else if (key->type == KEY_DSA) {  
                 buffer_put_string(b, sshname, strlen(sshname));  
                 buffer_put_bignum2(b, key->dsa->p);  
                 buffer_put_bignum2(b, key->dsa->q);  
                 buffer_put_bignum2(b, key->dsa->g);  
                 buffer_put_bignum2(b, key->dsa->pub_key);  
   
         } else {  
                 ret = 0;  
                 goto error;  
   
         }  
   
         len = buffer_len(b);  
         if (lenp != NULL)  
                 *lenp = len;  
         if (blobp != NULL) {  
                 *blobp = malloc(len);  
                 if (*blobp == NULL) {  
                         ret = 0;  
                         goto error;  
                 }  
                 memcpy(*blobp, buffer_ptr(b), len);  
         }  
   
 error:  
         buffer_free(b);  
   
         return (ret);  
 }  
   
   
 //  
 // バッファからキー情報を取り出す(for SSH2)  
 // NOTE: 返値はアロケート領域になるので、呼び出し側で解放すること。  
 //  
 Key *key_from_blob(char *data, int blen)  
 {  
         int keynamelen;  
         char key[128];  
         RSA *rsa = NULL;  
         DSA *dsa = NULL;  
         Key *hostkey;  // hostkey  
         enum hostkey_type type;  
   
         hostkey = malloc(sizeof(Key));  
         if (hostkey == NULL)  
                 goto error;  
   
         memset(hostkey, 0, sizeof(Key));  
   
         keynamelen = get_uint32_MSBfirst(data);  
         if (keynamelen >= sizeof(key)) {  
                 goto error;  
         }  
         data += 4;  
         memcpy(key, data, keynamelen);  
         key[keynamelen] = 0;  
         data += keynamelen;  
   
         type = get_keytype_from_name(key);  
   
                 // RSA key  
         if (type == KEY_RSA) {  
                 rsa = RSA_new();  
                 if (rsa == NULL) {  
                         goto error;  
                 }  
                 rsa->n = BN_new();  
                 rsa->e = BN_new();  
                 if (rsa->n == NULL || rsa->e == NULL) {  
                         goto error;  
                 }  
   
                 buffer_get_bignum2(&data, rsa->e);  
                 buffer_get_bignum2(&data, rsa->n);  
   
                 hostkey->type = type;  
                 hostkey->rsa = rsa;  
   
         } else if (type == KEY_DSA) { // DSA key  
                 dsa = DSA_new();  
                 if (dsa == NULL) {  
                         goto error;  
                 }  
                 dsa->p = BN_new();  
                 dsa->q = BN_new();  
                 dsa->g = BN_new();  
                 dsa->pub_key = BN_new();  
                 if (dsa->p == NULL ||  
                     dsa->q == NULL ||  
                     dsa->g == NULL ||  
                     dsa->pub_key == NULL) {  
                         goto error;  
                 }  
   
                 buffer_get_bignum2(&data, dsa->p);  
                 buffer_get_bignum2(&data, dsa->q);  
                 buffer_get_bignum2(&data, dsa->g);  
                 buffer_get_bignum2(&data, dsa->pub_key);  
   
                 hostkey->type = type;  
                 hostkey->dsa = dsa;  
   
         } else {  
                 // unknown key  
                 goto error;  
   
         }  
   
         return (hostkey);  
   
 error:  
         if (rsa != NULL)  
                 RSA_free(rsa);  
         if (dsa != NULL)  
                 DSA_free(dsa);  
   
         return NULL;  
 }  
   
   
4919  //  //
4920  // Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEXDH_REPLY:31)  // Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEXDH_REPLY:31)
4921  //  //
# Line 6197  error: Line 5191  error:
5191  }  }
5192    
5193    
   
   
 // SHA-1(160bit)/SHA-256(256bit)を求める  
 static unsigned char *kex_dh_gex_hash(char *client_version_string,  
                                       char *server_version_string,  
                                       char *ckexinit, int ckexinitlen,  
                                       char *skexinit, int skexinitlen,  
                                       u_char *serverhostkeyblob, int sbloblen,  
                                       int kexgex_min,  
                                       int kexgex_bits,  
                                       int kexgex_max,  
                                       BIGNUM *kexgex_p,  
                                       BIGNUM *kexgex_g,  
                                       BIGNUM *client_dh_pub,  
                                       enum kex_algorithm kex_type,  
                                       BIGNUM *server_dh_pub,  
                                       BIGNUM *shared_secret)  
 {  
         buffer_t *b;  
         static unsigned char digest[EVP_MAX_MD_SIZE];  
         const EVP_MD *evp_md = ssh2_kex_algorithms[kex_type].evp_md();  
         EVP_MD_CTX md;  
   
         b = buffer_init();  
         buffer_put_string(b, client_version_string, strlen(client_version_string));  
         buffer_put_string(b, server_version_string, strlen(server_version_string));  
   
         /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */  
         buffer_put_int(b, ckexinitlen+1);  
         buffer_put_char(b, SSH2_MSG_KEXINIT);  
         buffer_append(b, ckexinit, ckexinitlen);  
         buffer_put_int(b, skexinitlen+1);  
         buffer_put_char(b, SSH2_MSG_KEXINIT);  
         buffer_append(b, skexinit, skexinitlen);  
   
         buffer_put_string(b, serverhostkeyblob, sbloblen);  
   
         // DH group sizeのビット数を加算する  
         buffer_put_int(b, kexgex_min);  
         buffer_put_int(b, kexgex_bits);  
         buffer_put_int(b, kexgex_max);  
   
         // DH鍵の素数と生成元を加算する  
         buffer_put_bignum2(b, kexgex_p);  
         buffer_put_bignum2(b, kexgex_g);  
   
         buffer_put_bignum2(b, client_dh_pub);  
         buffer_put_bignum2(b, server_dh_pub);  
         buffer_put_bignum2(b, shared_secret);  
   
         // yutaka  
         //debug_print(38, buffer_ptr(b), buffer_len(b));  
   
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, buffer_ptr(b), buffer_len(b));  
         EVP_DigestFinal(&md, digest, NULL);  
   
         buffer_free(b);  
   
         //write_buffer_file(digest, EVP_MD_size(evp_md));  
   
         return digest;  
 }  
   
5194  // Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_DH_GEX_REPLY:33)  // Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_DH_GEX_REPLY:33)
5195  //  //
5196  // C then computes K = f^x mod p, H = hash(V_C ||  // C then computes K = f^x mod p, H = hash(V_C ||
# Line 6725  BOOL do_SSH2_userauth(PTInstVar pvar) Line 5655  BOOL do_SSH2_userauth(PTInstVar pvar)
5655  }  }
5656    
5657    
 static char *get_SSH2_keyname(CRYPTKeyPair *keypair)  
 {  
         char *s;  
   
         if (keypair->RSA_key != NULL) {  
                 s = "ssh-rsa";  
         } else {  
                 s = "ssh-dss";  
         }  
   
         return (s);  
 }  
   
   
 static BOOL generate_SSH2_keysign(CRYPTKeyPair *keypair, char **sigptr, int *siglen, char *data, int datalen)  
 {  
         buffer_t *msg = NULL;  
         char *s;  
   
         msg = buffer_init();  
         if (msg == NULL) {  
                 // TODO: error check  
                 return FALSE;  
         }  
   
         if (keypair->RSA_key != NULL) { // RSA  
                 const EVP_MD *evp_md;  
                 EVP_MD_CTX md;  
                 u_char digest[EVP_MAX_MD_SIZE], *sig;  
                 u_int slen, dlen, len;  
                 int ok, nid;  
   
                 nid = NID_sha1;  
                 if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {  
                         goto error;  
                 }  
   
                 // ダイジェスト値の計算  
                 EVP_DigestInit(&md, evp_md);  
                 EVP_DigestUpdate(&md, data, datalen);  
                 EVP_DigestFinal(&md, digest, &dlen);  
   
                 slen = RSA_size(keypair->RSA_key);  
                 sig = malloc(slen);  
                 if (sig == NULL)  
                         goto error;  
   
                 // 電子署名を計算  
                 ok = RSA_sign(nid, digest, dlen, sig, &len, keypair->RSA_key);  
                 memset(digest, 'd', sizeof(digest));  
                 if (ok != 1) { // error  
                         free(sig);  
                         goto error;  
                 }  
                 // 署名のサイズがバッファより小さい場合、後ろへずらす。先頭はゼロで埋める。  
                 if (len < slen) {  
                         u_int diff = slen - len;  
                         memmove(sig + diff, sig, len);  
                         memset(sig, 0, diff);  
   
                 } else if (len > slen) {  
                         free(sig);  
                         goto error;  
   
                 } else {  
                         // do nothing  
   
                 }  
   
                 s = get_SSH2_keyname(keypair);  
                 buffer_put_string(msg, s, strlen(s));  
                 buffer_append_length(msg, sig, slen);  
                 len = buffer_len(msg);  
   
                 // setting  
                 *siglen = len;  
                 *sigptr = malloc(len);  
                 if (*sigptr == NULL) {  
                         free(sig);  
                         goto error;  
                 }  
                 memcpy(*sigptr, buffer_ptr(msg), len);  
                 free(sig);  
   
         } else { // DSA  
                 DSA_SIG *sig;  
                 const EVP_MD *evp_md = EVP_sha1();  
                 EVP_MD_CTX md;  
                 u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN];  
                 u_int rlen, slen, len, dlen;  
   
                 // ダイジェストの計算  
                 EVP_DigestInit(&md, evp_md);  
                 EVP_DigestUpdate(&md, data, datalen);  
                 EVP_DigestFinal(&md, digest, &dlen);  
   
                 // DSA電子署名を計算  
                 sig = DSA_do_sign(digest, dlen, keypair->DSA_key);  
                 memset(digest, 'd', sizeof(digest));  
                 if (sig == NULL) {  
                         goto error;  
                 }  
   
                 // BIGNUMからバイナリ値への変換  
                 rlen = BN_num_bytes(sig->r);  
                 slen = BN_num_bytes(sig->s);  
                 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {  
                         DSA_SIG_free(sig);  
                         goto error;  
                 }  
                 memset(sigblob, 0, SIGBLOB_LEN);  
                 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);  
                 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);  
                 DSA_SIG_free(sig);  
   
                 // setting  
                 s = get_SSH2_keyname(keypair);  
                 buffer_put_string(msg, s, strlen(s));  
                 buffer_append_length(msg, sigblob, sizeof(sigblob));  
                 len = buffer_len(msg);  
   
                 // setting  
                 *siglen = len;  
                 *sigptr = malloc(len);  
                 if (*sigptr == NULL) {  
                         goto error;  
                 }  
                 memcpy(*sigptr, buffer_ptr(msg), len);  
   
         }  
   
         buffer_free(msg);  
         return TRUE;  
   
 error:  
         buffer_free(msg);  
   
         return FALSE;  
 }  
   
   
 static BOOL get_SSH2_publickey_blob(PTInstVar pvar, buffer_t **blobptr, int *bloblen)  
 {  
         buffer_t *msg = NULL;  
         CRYPTKeyPair *keypair;  
         char *s;  
   
         msg = buffer_init();  
         if (msg == NULL) {  
                 // TODO: error check  
                 return FALSE;  
         }  
   
         keypair = pvar->auth_state.cur_cred.key_pair;  
   
         if (keypair->RSA_key != NULL) { // RSA  
                 s = get_SSH2_keyname(keypair);  
                 buffer_put_string(msg, s, strlen(s));  
                 buffer_put_bignum2(msg, keypair->RSA_key->e); // 公開指数  
                 buffer_put_bignum2(msg, keypair->RSA_key->n); // p×q  
   
         } else { // DSA  
                 s = get_SSH2_keyname(keypair);  
                 buffer_put_string(msg, s, strlen(s));  
                 buffer_put_bignum2(msg, keypair->DSA_key->p); // 素数  
                 buffer_put_bignum2(msg, keypair->DSA_key->q); // (p-1)の素因数  
                 buffer_put_bignum2(msg, keypair->DSA_key->g); // 整数  
                 buffer_put_bignum2(msg, keypair->DSA_key->pub_key); // 公開鍵  
   
         }  
   
         *blobptr = msg;  
         *bloblen = buffer_len(msg);  
   
         return TRUE;  
 }  
   
5658  static BOOL handle_SSH2_service_accept(PTInstVar pvar)  static BOOL handle_SSH2_service_accept(PTInstVar pvar)
5659  {  {
5660          char *data, *s, tmp[100];          char *data, *s, tmp[100];

Legend:
Removed from v.4303  
changed lines
  Added in v.4304

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26