| 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> |
| 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> |
| 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 |
| 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__) |
| 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 |
// |
// |
| 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; |
| 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 |
| 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 |
// |
// |
| 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 || |
| 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]; |