static void build_session_id1(SSH_SESSION *session, STRING *servern, STRING *hostn){ MD5CTX md5=md5_init(); #ifdef DEBUG_CRYPTO ssh_print_hexa("host modulus",hostn->string,string_len(hostn)); ssh_print_hexa("server modulus",servern->string,string_len(servern)); #endif md5_update(md5,hostn->string,string_len(hostn)); md5_update(md5,servern->string,string_len(servern)); md5_update(md5,session->server_kex.cookie,8); md5_final(session->next_crypto->session_id,md5); #ifdef DEBUG_CRYPTO ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN); #endif }
int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,unsigned char *mac){ HMACCTX ctx; unsigned char hmacbuf[EVP_MAX_MD_SIZE]; unsigned int len; u32 seq=htonl(session->recv_seq); ctx=hmac_init(session->current_crypto->decryptMAC,20,HMAC_SHA1); hmac_update(ctx,(unsigned char *)&seq,sizeof(u32)); hmac_update(ctx,buffer_get(buffer),buffer_get_len(buffer)); hmac_final(ctx,hmacbuf,&len); #ifdef DEBUG_CRYPTO ssh_print_hexa("received mac",mac,len); ssh_print_hexa("Computed mac",hmacbuf,len); ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(u32)); #endif return memcmp(mac,hmacbuf,len); }
static void des3_1_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out, unsigned long len) { #ifdef DEBUG_CRYPTO ssh_print_hexa("Decrypt IV before", cipher->IV, 24); #endif DES_ncbc_encrypt(in, out, len, (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)), cipher->IV, 0); DES_ncbc_encrypt(out, in, len, (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)), (void*)((uint8_t*)cipher->IV + 8), 1); DES_ncbc_encrypt(in, out, len, cipher->key, (void*)((uint8_t*)cipher->IV + 16), 0); #ifdef DEBUG_CRYPTO ssh_print_hexa("Decrypt IV after", cipher->IV, 24); #endif }
int verify_knownhost(ssh_session session){ char *hexa; int state; char buf[10]; unsigned char *hash = NULL; int hlen; state=ssh_is_server_known(session); hlen = ssh_get_pubkey_hash(session, &hash); if (hlen < 0) { return -1; } switch(state){ case SSH_SERVER_KNOWN_OK: break; /* ok */ case SSH_SERVER_KNOWN_CHANGED: fprintf(stderr,"Host key for server changed : server's one is now :\n"); ssh_print_hexa("Public key hash",hash, hlen); free(hash); fprintf(stderr,"For security reason, connection will be stopped\n"); return -1; case SSH_SERVER_FOUND_OTHER: fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n"); fprintf(stderr,"An attacker might change the default server key to confuse your client" "into thinking the key does not exist\n" "We advise you to rerun the client with -d or -r for more safety.\n"); return -1; case SSH_SERVER_FILE_NOT_FOUND: fprintf(stderr,"Could not find known host file. If you accept the host key here,\n"); fprintf(stderr,"the file will be automatically created.\n"); /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); fprintf(stderr,"The server is unknown. Do you trust the host key ?\n"); fprintf(stderr, "Public key hash: %s\n", hexa); free(hexa); fgets(buf,sizeof(buf),stdin); if(strncasecmp(buf,"yes",3)!=0){ return -1; } fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n"); fgets(buf,sizeof(buf),stdin); if(strncasecmp(buf,"yes",3)==0){ if (ssh_write_knownhost(session) < 0) { free(hash); fprintf(stderr, "error %s\n", strerror(errno)); return -1; } } break; case SSH_SERVER_ERROR: free(hash); fprintf(stderr,"%s",ssh_get_error(session)); return -1; } free(hash); return 0; }
STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *svrkey, PUBLIC_KEY *hostkey,int slen, int hlen ){ unsigned char buffer[32]; int i; STRING *data1,*data2; /* first, generate a session key */ ssh_get_random(session->next_crypto->encryptkey,32,1); memcpy(buffer,session->next_crypto->encryptkey,32); memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey,32); #ifdef DEBUG_CRYPTO ssh_print_hexa("session key",buffer,32); #endif /* xor session key with session_id */ for (i=0;i<16;++i) buffer[i]^=session->next_crypto->session_id[i]; data1=string_new(32); string_fill(data1,buffer,32); if(ABS(hlen-slen)<128){ ssh_say(1,"Difference between server modulus and host modulus is only %d. It's illegal and may not work\n", ABS(hlen-slen)); } if(modulus_smaller(svrkey,hostkey)){ data2=ssh_encrypt_rsa1(session,data1,svrkey); free(data1); data1=ssh_encrypt_rsa1(session,data2,hostkey); } else { data2=ssh_encrypt_rsa1(session,data1,hostkey); free(data1); data1=ssh_encrypt_rsa1(session,data2,svrkey); } return data1; }
static STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *srvkey, PUBLIC_KEY *hostkey, int slen, int hlen) { unsigned char buffer[32] = {0}; int i; STRING *data1 = NULL; STRING *data2 = NULL; /* first, generate a session key */ ssh_get_random(session->next_crypto->encryptkey, 32, 1); memcpy(buffer, session->next_crypto->encryptkey, 32); memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32); #ifdef DEBUG_CRYPTO ssh_print_hexa("session key",buffer,32); #endif /* xor session key with session_id */ for (i = 0; i < 16; i++) { buffer[i] ^= session->next_crypto->session_id[i]; } data1 = string_new(32); if (data1 == NULL) { return NULL; } string_fill(data1, buffer, 32); if (ABS(hlen - slen) < 128){ ssh_log(session, SSH_LOG_FUNCTIONS, "Difference between server modulus and host modulus is only %d. " "It's illegal and may not work", ABS(hlen - slen)); } if (modulus_smaller(srvkey, hostkey)) { data2 = ssh_encrypt_rsa1(session, data1, srvkey); string_free(data1); data1 = NULL; if (data2 == NULL) { return NULL; } data1 = ssh_encrypt_rsa1(session, data2, hostkey); string_free(data2); if (data1 == NULL) { return NULL; } } else { data2 = ssh_encrypt_rsa1(session, data1, hostkey); string_free(data1); data1 = NULL; if (data2 == NULL) { return NULL; } data1 = ssh_encrypt_rsa1(session, data2, srvkey); string_free(data2); if (data1 == NULL) { return NULL; } } return data1; }
static void des3_1_decrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV) { #ifdef DEBUG_CRYPTO ssh_print_hexa("Decrypt IV before", IV, 24); #endif DES_ncbc_encrypt(in, out, len, cipher->key + 2 * sizeof(DES_key_schedule), IV, 0); DES_ncbc_encrypt(out, in, len, cipher->key + sizeof(DES_key_schedule), IV + 8, 1); DES_ncbc_encrypt(in, out, len, cipher->key, IV + 16, 0); #ifdef DEBUG_CRYPTO ssh_print_hexa("Decrypt IV after", IV, 24); #endif }
int dh_build_k(ssh_session session) { #ifdef HAVE_LIBCRYPTO bignum_CTX ctx = bignum_ctx_new(); if (ctx == NULL) { return -1; } #endif session->next_crypto->k = bignum_new(); if (session->next_crypto->k == NULL) { #ifdef HAVE_LIBCRYPTO bignum_ctx_free(ctx); #endif return -1; } /* the server and clients don't use the same numbers */ #ifdef HAVE_LIBGCRYPT if(session->client) { bignum_mod_exp(session->next_crypto->k, session->next_crypto->f, session->next_crypto->x, p); } else { bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, session->next_crypto->y, p); } #elif defined HAVE_LIBCRYPTO if (session->client) { bignum_mod_exp(session->next_crypto->k, session->next_crypto->f, session->next_crypto->x, p, ctx); } else { bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, session->next_crypto->y, p, ctx); } #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("Session server cookie", session->server_kex.cookie, 16); ssh_print_hexa("Session client cookie", session->client_kex.cookie, 16); ssh_print_bignum("Shared secret key", session->next_crypto->k); #endif #ifdef HAVE_LIBCRYPTO bignum_ctx_free(ctx); #endif return 0; }
/* this function signs the session id */ STRING *ssh_sign_session_id(SSH_SESSION *session, PRIVATE_KEY *privatekey){ SHACTX ctx; unsigned char hash[SHA_DIGEST_LEN+1]; SIGNATURE *sign; STRING *signature; CRYPTO *crypto=session->current_crypto?session->current_crypto:session->next_crypto; #ifdef HAVE_LIBGCRYPT gcry_sexp_t data_sexp; #endif ctx=sha1_init(); sha1_update(ctx,crypto->session_id,SHA_DIGEST_LEN); sha1_final(hash+1,ctx); hash[0]=0; #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed with dsa",hash+1,SHA_DIGEST_LEN); #endif sign=malloc(sizeof(SIGNATURE)); switch(privatekey->type){ case TYPE_DSS: #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&data_sexp,NULL,"%b",SHA_DIGEST_LEN+1,hash); gcry_pk_sign(&sign->dsa_sign,data_sexp,privatekey->dsa_priv); #elif defined HAVE_LIBCRYPTO sign->dsa_sign=DSA_do_sign(hash+1,SHA_DIGEST_LEN,privatekey->dsa_priv); #ifdef DEBUG_CRYPTO ssh_print_bignum("r",sign->dsa_sign->r); ssh_print_bignum("s",sign->dsa_sign->s); #endif #endif sign->rsa_sign=NULL; break; case TYPE_RSA: #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&data_sexp,NULL,"(data(flags pkcs1)(hash sha1 %b))",SHA_DIGEST_LEN,hash+1); gcry_pk_sign(&sign->rsa_sign,data_sexp,privatekey->rsa_priv); #elif defined HAVE_LIBCRYPTO sign->rsa_sign=RSA_do_sign(hash+1,SHA_DIGEST_LEN,privatekey->rsa_priv); #endif sign->dsa_sign=NULL; break; } #ifdef HAVE_LIBGCRYPT gcry_sexp_release(data_sexp); #endif sign->type=privatekey->type; if(!sign->dsa_sign && !sign->rsa_sign){ #ifdef HAVE_LIBGCRYPT ssh_set_error(session,SSH_FATAL,"Signing : libgcrypt error"); #elif defined HAVE_LIBCRYPTO ssh_set_error(session,SSH_FATAL,"Signing : openssl error"); #endif signature_free(sign); return NULL; } signature=signature_to_string(sign); signature_free(sign); return signature; }
void ssh_list_kex(KEX *kex){ int i=0; #ifdef DEBUG_CRYPTO ssh_print_hexa("session cookie",kex->cookie,16); #endif for(i=0;i<10;i++){ ssh_say(2,"%s : %s\n",ssh_kex_nums[i],kex->methods[i]); } }
unsigned char * packet_encrypt(SSH_SESSION *session,void *data,u32 len){ struct crypto_struct *crypto; HMACCTX ctx; char *out; unsigned int finallen; u32 seq=ntohl(session->send_seq); if(!session->current_crypto) return NULL; /* nothing to do here */ crypto= session->current_crypto->out_cipher; ssh_log(session,SSH_LOG_PACKET,"encrypting packet with seq num: %d, len: %d",session->send_seq,len); #ifdef HAVE_LIBGCRYPT crypto->set_encrypt_key(crypto,session->current_crypto->encryptkey,session->current_crypto->encryptIV); #elif defined HAVE_LIBCRYPTO crypto->set_encrypt_key(crypto,session->current_crypto->encryptkey); #endif out=malloc(len); if(session->version==2){ ctx=hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1); hmac_update(ctx,(unsigned char *)&seq,sizeof(u32)); hmac_update(ctx,data,len); hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); #ifdef DEBUG_CRYPTO ssh_print_hexa("mac :",data,len); if(finallen!=20) printf("Final len is %d\n",finallen); ssh_print_hexa("packet hmac",session->current_crypto->hmacbuf,20); #endif } #ifdef HAVE_LIBGCRYPT crypto->cbc_encrypt(crypto,data,out,len); #elif defined HAVE_LIBCRYPTO crypto->cbc_encrypt(crypto,data,out,len,session->current_crypto->encryptIV); #endif memcpy(data,out,len); memset(out,0,len); free(out); if(session->version==2) return session->current_crypto->hmacbuf; else return NULL; }
void ssh_list_kex(struct ssh_session *session, KEX *kex) { int i = 0; #ifdef DEBUG_CRYPTO ssh_print_hexa("session cookie", kex->cookie, 16); #endif for(i = 0; i < 10; i++) { ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s", ssh_kex_nums[i], kex->methods[i]); } }
static int build_session_id1(ssh_session session, ssh_string servern, ssh_string hostn) { MD5CTX md5 = NULL; md5 = md5_init(); if (md5 == NULL) { return -1; } #ifdef DEBUG_CRYPTO ssh_print_hexa("host modulus",ssh_string_data(hostn),ssh_string_len(hostn)); ssh_print_hexa("server modulus",ssh_string_data(servern),ssh_string_len(servern)); #endif md5_update(md5,ssh_string_data(hostn),ssh_string_len(hostn)); md5_update(md5,ssh_string_data(servern),ssh_string_len(servern)); md5_update(md5,session->server_kex.cookie,8); md5_final(session->next_crypto->session_id,md5); #ifdef DEBUG_CRYPTO ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN); #endif return 0; }
/** * @internal * * @brief Verify the hmac of a packet * * @param session The session to use. * @param buffer The buffer to verify the hmac from. * @param mac The mac to compare with the hmac. * * @return 0 if hmac and mac are equal, < 0 if not or an error * occurred. */ int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer, uint8_t *mac, enum ssh_hmac_e type) { unsigned char hmacbuf[DIGEST_MAX_LEN] = {0}; HMACCTX ctx; unsigned int len; uint32_t seq; /* AEAD type have no mac checking */ if (type == SSH_HMAC_AEAD_POLY1305) { return SSH_OK; } ctx = hmac_init(session->current_crypto->decryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { return -1; } seq = htonl(session->recv_seq); hmac_update(ctx, (unsigned char *) &seq, sizeof(uint32_t)); hmac_update(ctx, ssh_buffer_get(buffer), ssh_buffer_get_len(buffer)); hmac_final(ctx, hmacbuf, &len); #ifdef DEBUG_CRYPTO ssh_print_hexa("received mac",mac,len); ssh_print_hexa("Computed mac",hmacbuf,len); ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t)); #endif if (secure_memcmp(mac, hmacbuf, len) == 0) { return 0; } return -1; }
void ssh_list_kex(struct ssh_kex_struct *kex) { int i = 0; #ifdef DEBUG_CRYPTO ssh_print_hexa("session cookie", kex->cookie, 16); #endif for(i = 0; i < SSH_KEX_METHODS; i++) { if (kex->methods[i] == NULL) { continue; } SSH_LOG(SSH_LOG_FUNCTIONS, "%s: %s", ssh_kex_descriptions[i], kex->methods[i]); } }
void ssh_list_kex(ssh_session session, KEX *kex) { int i = 0; #ifdef DEBUG_CRYPTO ssh_print_hexa("session cookie", kex->cookie, 16); #endif if(kex->methods==NULL){ ssh_log(session, SSH_LOG_RARE,"kex->methods is NULL"); return; } for(i = 0; i < 10; i++) { ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s", ssh_kex_nums[i], kex->methods[i]); } }
/* * This function signs the session id (known as H) as a string then * the content of sigbuf */ ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, ssh_key privatekey) { struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto : session->next_crypto; unsigned char hash[SHA_DIGEST_LEN + 1] = {0}; ssh_string session_str = NULL; ssh_string signature = NULL; struct signature_struct *sign = NULL; SHACTX ctx = NULL; if (privatekey == NULL || !ssh_key_is_private(privatekey)) { return NULL; } session_str = ssh_string_new(SHA_DIGEST_LEN); if (session_str == NULL) { return NULL; } ssh_string_fill(session_str, crypto->session_id, SHA_DIGEST_LEN); ctx = sha1_init(); if (ctx == NULL) { ssh_string_free(session_str); return NULL; } sha1_update(ctx, session_str, ssh_string_len(session_str) + 4); ssh_string_free(session_str); sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); sha1_final(hash + 1,ctx); hash[0] = 0; #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed with dsa", hash + 1, SHA_DIGEST_LEN); #endif sign = pki_do_sign(privatekey, hash); if (sign == NULL) { return NULL; } signature = signature_to_string(sign); signature_free(sign); return signature; }
/* this function signs the session id */ ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey) { struct ssh_crypto_struct *crypto=session->current_crypto ? session->current_crypto : session->next_crypto; unsigned char hash[SHA_DIGEST_LEN + 1] = {0}; ssh_string signature = NULL; SIGNATURE *sign = NULL; SHACTX ctx = NULL; #ifdef HAVE_LIBGCRYPT gcry_sexp_t data_sexp; #endif ctx = sha1_init(); if (ctx == NULL) { return NULL; } sha1_update(ctx,crypto->session_id,SHA_DIGEST_LEN); sha1_final(hash + 1,ctx); hash[0] = 0; #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed with dsa",hash+1,SHA_DIGEST_LEN); #endif sign = malloc(sizeof(SIGNATURE)); if (sign == NULL) { return NULL; } ZERO_STRUCTP(sign); switch(privatekey->type) { case SSH_KEYTYPE_DSS: #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&data_sexp, NULL, "%b", SHA_DIGEST_LEN + 1, hash) || gcry_pk_sign(&sign->dsa_sign, data_sexp, privatekey->dsa_priv)) { ssh_set_error(session, SSH_FATAL, "Signing: libgcrypt error"); gcry_sexp_release(data_sexp); signature_free(sign); return NULL; } #elif defined HAVE_LIBCRYPTO sign->dsa_sign = DSA_do_sign(hash + 1, SHA_DIGEST_LEN, privatekey->dsa_priv); if (sign->dsa_sign == NULL) { ssh_set_error(session, SSH_FATAL, "Signing: openssl error"); signature_free(sign); return NULL; } #ifdef DEBUG_CRYPTO ssh_print_bignum("r",sign->dsa_sign->r); ssh_print_bignum("s",sign->dsa_sign->s); #endif #endif /* HAVE_LIBCRYPTO */ sign->rsa_sign = NULL; break; case SSH_KEYTYPE_RSA: #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(hash sha1 %b))", SHA_DIGEST_LEN, hash + 1) || gcry_pk_sign(&sign->rsa_sign, data_sexp, privatekey->rsa_priv)) { ssh_set_error(session, SSH_FATAL, "Signing: libgcrypt error"); gcry_sexp_release(data_sexp); signature_free(sign); return NULL; } #elif defined HAVE_LIBCRYPTO sign->rsa_sign = RSA_do_sign(hash + 1, SHA_DIGEST_LEN, privatekey->rsa_priv); if (sign->rsa_sign == NULL) { ssh_set_error(session, SSH_FATAL, "Signing: openssl error"); signature_free(sign); return NULL; } #endif sign->dsa_sign = NULL; break; default: signature_free(sign); return NULL; } #ifdef HAVE_LIBGCRYPT gcry_sexp_release(data_sexp); #endif sign->type = privatekey->type; signature = signature_to_string(sign); signature_free(sign); return signature; }
/* TODO : split this function in two so it becomes smaller */ SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,PUBLIC_KEY *pubkey,int needed_type){ #ifdef HAVE_LIBGCRYPT gcry_sexp_t sig; #elif defined HAVE_LIBCRYPTO DSA_SIG *sig; STRING *r,*s; #endif SIGNATURE *sign=malloc(sizeof(SIGNATURE)); BUFFER *tmpbuf=buffer_new(); STRING *rs; STRING *type_s,*e; int len,rsalen; char *type; buffer_add_data(tmpbuf,signature->string,string_len(signature)); type_s=buffer_get_ssh_string(tmpbuf); if(!type_s){ ssh_set_error(session,SSH_FATAL,"Invalid signature packet"); buffer_free(tmpbuf); return NULL; } type=string_to_char(type_s); free(type_s); switch(needed_type){ case TYPE_DSS: if(strcmp(type,"ssh-dss")){ ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); buffer_free(tmpbuf); free(type); return NULL; } break; case TYPE_RSA: if(strcmp(type,"ssh-rsa")){ ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); buffer_free(tmpbuf); free(type); return NULL; } break; default: ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type); free(type); buffer_free(tmpbuf); return NULL; } free(type); switch(needed_type){ case TYPE_DSS: rs=buffer_get_ssh_string(tmpbuf); buffer_free(tmpbuf); if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */ if(rs) free(rs); return NULL; } /* we make use of strings (because we have all-made functions to convert them to bignums (ou pas ;)*/ #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&sig,NULL,"(sig-val(dsa(r %b)(s %b)))",20,rs->string,20,rs->string+20); #elif defined HAVE_LIBCRYPTO r=string_new(20); s=string_new(20); string_fill(r,rs->string,20); string_fill(s,rs->string+20,20); sig=DSA_SIG_new(); sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ sig->s=make_string_bn(s); free(r); free(s); #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("r",rs->string,20); ssh_print_hexa("s",rs->string+20,20); #endif free(rs); sign->type=TYPE_DSS; sign->dsa_sign=sig; return sign; case TYPE_RSA: e=buffer_get_ssh_string(tmpbuf); buffer_free(tmpbuf); if(!e){ return NULL; } len=string_len(e); #ifdef HAVE_LIBGCRYPT rsalen=(gcry_pk_get_nbits(pubkey->rsa_pub)+7)/8; #elif defined HAVE_LIBCRYPTO rsalen=RSA_size(pubkey->rsa_pub); #endif if(len>rsalen){ free(e); free(sign); ssh_set_error(session,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen); return NULL; } if(len<rsalen) ssh_log(session,SSH_LOG_RARE,"RSA signature len %d < %d",len,rsalen); sign->type=TYPE_RSA; #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&sig,NULL,"(sig-val(rsa(s %b)))",string_len(e),e->string); sign->rsa_sign=sig; #elif defined HAVE_LIBCRYPTO sign->rsa_sign=e; #endif #ifdef DEBUG_CRYPTO ssh_say(0,"Len : %d\n",len); ssh_print_hexa("rsa signature",e->string,len); #endif #ifdef HAVE_LIBGCRYPT free(e); #endif return sign; default: return NULL; } }
static int pki_import_pubkey_buffer(ssh_buffer buffer, enum ssh_keytypes_e type, ssh_key *pkey) { ssh_key key; int rc; key = ssh_key_new(); if (key == NULL) { return SSH_ERROR; } key->type = type; key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PUBLIC; switch (type) { case SSH_KEYTYPE_DSS: { ssh_string p; ssh_string q; ssh_string g; ssh_string pubkey; p = ssh_buffer_get_ssh_string(buffer); if (p == NULL) { goto fail; } q = ssh_buffer_get_ssh_string(buffer); if (q == NULL) { ssh_string_burn(p); ssh_string_free(p); goto fail; } g = ssh_buffer_get_ssh_string(buffer); if (g == NULL) { ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); goto fail; } pubkey = ssh_buffer_get_ssh_string(buffer); if (pubkey == NULL) { ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); goto fail; } rc = pki_pubkey_build_dss(key, p, q, g, pubkey); #ifdef DEBUG_CRYPTO ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p)); ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q)); ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g)); #endif ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); if (rc == SSH_ERROR) { goto fail; } } break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: { ssh_string e; ssh_string n; e = ssh_buffer_get_ssh_string(buffer); if (e == NULL) { goto fail; } n = ssh_buffer_get_ssh_string(buffer); if (n == NULL) { ssh_string_burn(e); ssh_string_free(e); goto fail; } rc = pki_pubkey_build_rsa(key, e, n); #ifdef DEBUG_CRYPTO ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e)); ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n)); #endif ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); if (rc == SSH_ERROR) { goto fail; } } break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_ECC { ssh_string e; ssh_string i; int nid; i = ssh_buffer_get_ssh_string(buffer); if (i == NULL) { goto fail; } nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i)); ssh_string_free(i); if (nid == -1) { goto fail; } e = ssh_buffer_get_ssh_string(buffer); if (e == NULL) { goto fail; } rc = pki_pubkey_build_ecdsa(key, nid, e); ssh_string_burn(e); ssh_string_free(e); if (rc < 0) { goto fail; } /* Update key type */ key->type_c = ssh_pki_key_ecdsa_name(key); } break; #endif case SSH_KEYTYPE_ED25519: { ssh_string pubkey = ssh_buffer_get_ssh_string(buffer); if (ssh_string_len(pubkey) != ED25519_PK_LEN) { SSH_LOG(SSH_LOG_WARN, "Invalid public key length"); ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } key->ed25519_pubkey = malloc(ED25519_PK_LEN); if (key->ed25519_pubkey == NULL) { ssh_string_burn(pubkey); ssh_string_free(pubkey); goto fail; } memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN); ssh_string_burn(pubkey); ssh_string_free(pubkey); } break; case SSH_KEYTYPE_DSS_CERT01: case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: default: SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type); goto fail; } *pkey = key; return SSH_OK; fail: ssh_key_free(key); return SSH_ERROR; }
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, const ssh_key privkey) { struct ssh_crypto_struct *crypto; ssh_signature sig = NULL; ssh_string sig_blob; int rc; if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) { return NULL; } crypto = session->next_crypto ? session->next_crypto : session->current_crypto; if (crypto->secret_hash == NULL){ ssh_set_error(session,SSH_FATAL,"Missing secret_hash"); return NULL; } if (privkey->type == SSH_KEYTYPE_ECDSA) { #ifdef HAVE_ECC unsigned char ehash[EVP_DIGEST_LEN] = {0}; uint32_t elen; evp(privkey->ecdsa_nid, crypto->secret_hash, crypto->digest_len, ehash, &elen); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", ehash, elen); #endif sig = pki_do_sign_sessionid(privkey, ehash, elen); if (sig == NULL) { return NULL; } #endif } else if (privkey->type == SSH_KEYTYPE_ED25519) { sig = ssh_signature_new(); if (sig == NULL){ return NULL; } sig->type = privkey->type; sig->type_c = privkey->type_c; rc = pki_ed25519_sign(privkey, sig, crypto->secret_hash, crypto->digest_len); if (rc != SSH_OK){ ssh_signature_free(sig); sig = NULL; } } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; SHACTX ctx; ctx = sha1_init(); if (ctx == NULL) { return NULL; } sha1_update(ctx, crypto->secret_hash, crypto->digest_len); sha1_final(hash, ctx); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); #endif sig = pki_do_sign_sessionid(privkey, hash, SHA_DIGEST_LEN); if (sig == NULL) { return NULL; } } rc = ssh_pki_export_signature_blob(sig, &sig_blob); ssh_signature_free(sig); if (rc < 0) { return NULL; } return sig_blob; }
/* TODO : split this function in two so it becomes smaller */ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature, ssh_public_key pubkey, int needed_type) { SIGNATURE *sign = NULL; ssh_buffer tmpbuf = NULL; ssh_string rs = NULL; ssh_string type_s = NULL; ssh_string e = NULL; char *type_c = NULL; int type; int len; int rsalen; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sig; #elif defined HAVE_LIBCRYPTO DSA_SIG *sig = NULL; ssh_string r = NULL; ssh_string s = NULL; #endif sign = malloc(sizeof(SIGNATURE)); if (sign == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return NULL; } ZERO_STRUCTP(sign); tmpbuf = ssh_buffer_new(); if (tmpbuf == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); signature_free(sign); return NULL; } if (buffer_add_data(tmpbuf, ssh_string_data(signature), ssh_string_len(signature)) < 0) { signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type_s = buffer_get_ssh_string(tmpbuf); if (type_s == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid signature packet"); signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type_c = ssh_string_to_char(type_s); ssh_string_free(type_s); if (type_c == NULL) { signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } type = ssh_type_from_name(type_c); SAFE_FREE(type_c); if (needed_type != type) { ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s", ssh_type_to_char(type)); signature_free(sign); ssh_buffer_free(tmpbuf); return NULL; } switch(needed_type) { case SSH_KEYTYPE_DSS: rs = buffer_get_ssh_string(tmpbuf); ssh_buffer_free(tmpbuf); /* 40 is the dual signature blob len. */ if (rs == NULL || ssh_string_len(rs) != 40) { ssh_string_free(rs); signature_free(sign); return NULL; } /* we make use of strings (because we have all-made functions to convert * them to bignums (ou pas ;) */ #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&sig, NULL, "(sig-val(dsa(r %b)(s %b)))", 20 ,ssh_string_data(rs), 20,(unsigned char *)ssh_string_data(rs) + 20)) { ssh_string_free(rs); signature_free(sign); return NULL; } #elif defined HAVE_LIBCRYPTO r = ssh_string_new(20); s = ssh_string_new(20); if (r == NULL || s == NULL) { ssh_string_free(r); ssh_string_free(s); ssh_string_free(rs); signature_free(sign); return NULL; } ssh_string_fill(r, ssh_string_data(rs), 20); ssh_string_fill(s, (char *)ssh_string_data(rs) + 20, 20); sig = DSA_SIG_new(); if (sig == NULL) { ssh_string_free(r); ssh_string_free(s); ssh_string_free(rs); signature_free(sign); return NULL; } sig->r = make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ sig->s = make_string_bn(s); ssh_string_free(r); ssh_string_free(s); if (sig->r == NULL || sig->s == NULL) { ssh_string_free(rs); DSA_SIG_free(sig); signature_free(sign); return NULL; } #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("r", ssh_string_data(rs), 20); ssh_print_hexa("s", (const unsigned char *)ssh_string_data(rs) + 20, 20); #endif ssh_string_free(rs); sign->type = SSH_KEYTYPE_DSS; sign->dsa_sign = sig; return sign; case SSH_KEYTYPE_RSA: e = buffer_get_ssh_string(tmpbuf); ssh_buffer_free(tmpbuf); if (e == NULL) { signature_free(sign); return NULL; } len = ssh_string_len(e); #ifdef HAVE_LIBGCRYPT rsalen = (gcry_pk_get_nbits(pubkey->rsa_pub) + 7) / 8; #elif defined HAVE_LIBCRYPTO rsalen = RSA_size(pubkey->rsa_pub); #endif if (len > rsalen) { ssh_string_free(e); signature_free(sign); ssh_set_error(session, SSH_FATAL, "Signature too big! %d instead of %d", len, rsalen); return NULL; } if (len < rsalen) { ssh_log(session, SSH_LOG_RARE, "RSA signature len %d < %d", len, rsalen); } sign->type = SSH_KEYTYPE_RSA; #ifdef HAVE_LIBGCRYPT if (gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))", ssh_string_len(e), ssh_string_data(e))) { signature_free(sign); ssh_string_free(e); return NULL; } sign->rsa_sign = sig; #elif defined HAVE_LIBCRYPTO sign->rsa_sign = e; #endif #ifdef DEBUG_CRYPTO ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len); ssh_print_hexa("RSA signature", ssh_string_data(e), len); #endif #ifdef HAVE_LIBGCRYPT ssh_string_free(e); #endif return sign; default: return NULL; } return NULL; }
int verify_knownhost(ssh_session session) { int state, hlen; unsigned char *hash = NULL; char *hexa; char buf[10]; state = ssh_is_server_known(session); hlen = ssh_get_pubkey_hash(session, &hash); if (hlen < 0) return -1; switch (state) { case SSH_SERVER_KNOWN_OK: break; /* ok */ case SSH_SERVER_KNOWN_CHANGED: fprintf(stderr, "Host key for server changed: it is now:\n"); ssh_print_hexa("Public key hash", hash, hlen); fprintf(stderr, "For security reasons, connection will be stopped\n"); free(hash); return -1; case SSH_SERVER_FOUND_OTHER: fprintf(stderr, "The host key for this server was not found but an other" "type of key exists.\n"); fprintf(stderr, "An attacker might change the default server key to" "confuse your client into thinking the key does not exist\n"); free(hash); return -1; case SSH_SERVER_FILE_NOT_FOUND: fprintf(stderr, "Could not find known host file.\n"); fprintf(stderr, "If you accept the host key here, the file will be" "automatically created.\n"); /* fallback to SSH_SERVER_NOT_KNOWN behavior */ case SSH_SERVER_NOT_KNOWN: hexa = ssh_get_hexa(hash, hlen); fprintf(stderr,"The server is unknown. Do you trust the host key [yes/no]?\n"); fprintf(stderr, "Public key hash: %s\n", hexa); free(hexa); if (fgets(buf, sizeof(buf), stdin) == NULL) { free(hash); return -1; } if (strncasecmp(buf, "yes", 3) != 0) { free(hash); return -1; } if (ssh_write_knownhost(session) < 0) { fprintf(stderr, "Error %s\n", strerror(errno)); free(hash); return -1; } break; case SSH_SERVER_ERROR: fprintf(stderr, "Error %s", ssh_get_error(session)); free(hash); return -1; } free(hash); return 0; }
int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user) { void *packet = NULL; int to_be_read; size_t processed=0; uint32_t padding; uint32_t crc; uint32_t len, buffer_len; ssh_session session=(ssh_session)user; switch (session->packet_state){ case PACKET_STATE_INIT: memset(&session->in_packet, 0, sizeof(PACKET)); if (session->in_buffer) { if (ssh_buffer_reinit(session->in_buffer) < 0) { goto error; } } else { session->in_buffer = ssh_buffer_new(); if (session->in_buffer == NULL) { goto error; } } /* must have at least enough bytes for size */ if(receivedlen < sizeof(uint32_t)){ return 0; } memcpy(&len,data,sizeof(uint32_t)); processed += sizeof(uint32_t); /* len is not encrypted */ len = ntohl(len); if (len > MAX_PACKET_LEN) { ssh_set_error(session, SSH_FATAL, "read_packet(): Packet len too high (%u %.8x)", len, len); goto error; } SSH_LOG(SSH_LOG_PACKET, "Reading a %d bytes packet", len); session->in_packet.len = len; session->packet_state = PACKET_STATE_SIZEREAD; /* FALL THROUGH */ case PACKET_STATE_SIZEREAD: len = session->in_packet.len; /* SSH-1 has a fixed padding lenght */ padding = 8 - (len % 8); to_be_read = len + padding; if(to_be_read + processed > receivedlen){ /* wait for rest of packet */ return processed; } /* it is _not_ possible that to_be_read be < 8. */ packet = (char *)data + processed; if (ssh_buffer_add_data(session->in_buffer,packet,to_be_read) < 0) { goto error; } processed += to_be_read; #ifdef DEBUG_CRYPTO ssh_print_hexa("read packet:", ssh_buffer_get(session->in_buffer), ssh_buffer_get_len(session->in_buffer)); #endif if (session->current_crypto) { /* * We decrypt everything, missing the lenght part (which was * previously read, unencrypted, and is not part of the buffer */ buffer_len = ssh_buffer_get_len(session->in_buffer); if (buffer_len > 0) { int rc; rc = ssh_packet_decrypt(session, ssh_buffer_get(session->in_buffer), buffer_len); if (rc < 0) { ssh_set_error(session, SSH_FATAL, "Packet decrypt error"); goto error; } } } #ifdef DEBUG_CRYPTO ssh_print_hexa("read packet decrypted:", ssh_buffer_get(session->in_buffer), ssh_buffer_get_len(session->in_buffer)); #endif SSH_LOG(SSH_LOG_PACKET, "%d bytes padding", padding); if(((len + padding) != ssh_buffer_get_len(session->in_buffer)) || ((len + padding) < sizeof(uint32_t))) { SSH_LOG(SSH_LOG_RARE, "no crc32 in packet"); ssh_set_error(session, SSH_FATAL, "no crc32 in packet"); goto error; } memcpy(&crc, (unsigned char *)ssh_buffer_get(session->in_buffer) + (len+padding) - sizeof(uint32_t), sizeof(uint32_t)); ssh_buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t)); crc = ntohl(crc); if (ssh_crc32(ssh_buffer_get(session->in_buffer), (len + padding) - sizeof(uint32_t)) != crc) { #ifdef DEBUG_CRYPTO ssh_print_hexa("crc32 on",ssh_buffer_get(session->in_buffer), len + padding - sizeof(uint32_t)); #endif SSH_LOG(SSH_LOG_RARE, "Invalid crc32"); ssh_set_error(session, SSH_FATAL, "Invalid crc32: expected %.8x, got %.8x", crc, ssh_crc32(ssh_buffer_get(session->in_buffer), len + padding - sizeof(uint32_t))); goto error; } /* pass the padding */ ssh_buffer_pass_bytes(session->in_buffer, padding); SSH_LOG(SSH_LOG_PACKET, "The packet is valid"); /* TODO FIXME #ifdef WITH_ZLIB if(session->current_crypto && session->current_crypto->do_compress_in){ decompress_buffer(session,session->in_buffer); } #endif */ session->recv_seq++; /* We don't want to rewrite a new packet while still executing the packet callbacks */ session->packet_state = PACKET_STATE_PROCESSING; ssh_packet_parse_type(session); /* execute callbacks */ ssh_packet_process(session, session->in_packet.type); session->packet_state = PACKET_STATE_INIT; if(processed < receivedlen){ int rc; /* Handle a potential packet left in socket buffer */ SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer", receivedlen-processed); rc = ssh_packet_socket_callback1((char *)data + processed, receivedlen - processed,user); processed += rc; } return processed; case PACKET_STATE_PROCESSING: SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying."); return 0; } error: session->session_state=SSH_SESSION_STATE_ERROR; return processed; }
static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey, ssh_public_key hostkey, int slen, int hlen) { unsigned char buffer[32] = {0}; int i; ssh_string data1 = NULL; ssh_string data2 = NULL; if(session->next_crypto->encryptkey != NULL) SAFE_FREE(session->next_crypto->encryptkey); if(session->next_crypto->decryptkey != NULL) SAFE_FREE(session->next_crypto->decryptkey); if(session->next_crypto->encryptIV != NULL) SAFE_FREE(session->next_crypto->encryptIV); if(session->next_crypto->decryptIV != NULL) SAFE_FREE(session->next_crypto->decryptIV); session->next_crypto->encryptkey = malloc(32); session->next_crypto->decryptkey = malloc(32); session->next_crypto->encryptIV = malloc(32); session->next_crypto->decryptIV = malloc(32); if(session->next_crypto->encryptkey == NULL || session->next_crypto->decryptkey == NULL || session->next_crypto->encryptIV == NULL || session->next_crypto->decryptIV == NULL){ ssh_set_error_oom(session); return NULL; } /* first, generate a session key */ ssh_get_random(session->next_crypto->encryptkey, 32, 1); memcpy(buffer, session->next_crypto->encryptkey, 32); memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32); memset(session->next_crypto->encryptIV, 0, 32); memset(session->next_crypto->decryptIV, 0, 32); #ifdef DEBUG_CRYPTO ssh_print_hexa("session key",buffer,32); #endif /* xor session key with session_id */ for (i = 0; i < 16; i++) { buffer[i] ^= session->next_crypto->session_id[i]; } data1 = ssh_string_new(32); if (data1 == NULL) { return NULL; } ssh_string_fill(data1, buffer, 32); if (ABS(hlen - slen) < 128){ SSH_LOG(SSH_LOG_FUNCTIONS, "Difference between server modulus and host modulus is only %d. " "It's illegal and may not work", ABS(hlen - slen)); } if (modulus_smaller(srvkey, hostkey)) { data2 = ssh_encrypt_rsa1(session, data1, srvkey); ssh_string_free(data1); data1 = NULL; if (data2 == NULL) { return NULL; } data1 = ssh_encrypt_rsa1(session, data2, hostkey); ssh_string_free(data2); if (data1 == NULL) { return NULL; } } else { data2 = ssh_encrypt_rsa1(session, data1, hostkey); ssh_string_free(data1); data1 = NULL; if (data2 == NULL) { return NULL; } data1 = ssh_encrypt_rsa1(session, data2, srvkey); ssh_string_free(data2); if (data1 == NULL) { return NULL; } } return data1; }
ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer, int type) { ssh_string e = NULL; ssh_string n = NULL; ssh_public_key key = NULL; key = malloc(sizeof(struct ssh_public_key_struct)); if (key == NULL) { ssh_buffer_free(buffer); return NULL; } ZERO_STRUCTP(key); key->type = type; key->type_c = ssh_type_to_char(key->type); e = buffer_get_ssh_string(buffer); n = buffer_get_ssh_string(buffer); ssh_buffer_free(buffer); /* we don't need it anymore */ if(e == NULL || n == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid RSA public key"); goto error; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->rsa_pub, NULL, "(public-key(rsa(n %b)(e %b)))", ssh_string_len(n), ssh_string_data(n), ssh_string_len(e),ssh_string_data(e)); if (key->rsa_pub == NULL) { goto error; } #elif HAVE_LIBCRYPTO key->rsa_pub = RSA_new(); if (key->rsa_pub == NULL) { goto error; } key->rsa_pub->e = make_string_bn(e); key->rsa_pub->n = make_string_bn(n); if (key->rsa_pub->e == NULL || key->rsa_pub->n == NULL) { goto error; } #endif #ifdef DEBUG_CRYPTO ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e)); ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n)); #endif ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); return key; error: ssh_string_burn(e); ssh_string_free(e); ssh_string_burn(n); ssh_string_free(n); publickey_free(key); return NULL; }
ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) { ssh_string p = NULL; ssh_string q = NULL; ssh_string g = NULL; ssh_string pubkey = NULL; ssh_public_key key = NULL; key = malloc(sizeof(struct ssh_public_key_struct)); if (key == NULL) { ssh_buffer_free(buffer); return NULL; } ZERO_STRUCTP(key); key->type = SSH_KEYTYPE_DSS; key->type_c = ssh_type_to_char(key->type); p = buffer_get_ssh_string(buffer); q = buffer_get_ssh_string(buffer); g = buffer_get_ssh_string(buffer); pubkey = buffer_get_ssh_string(buffer); ssh_buffer_free(buffer); /* we don't need it anymore */ if (p == NULL || q == NULL || g == NULL || pubkey == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid DSA public key"); goto error; } #ifdef HAVE_LIBGCRYPT gcry_sexp_build(&key->dsa_pub, NULL, "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))", ssh_string_len(p), ssh_string_data(p), ssh_string_len(q), ssh_string_data(q), ssh_string_len(g), ssh_string_data(g), ssh_string_len(pubkey), ssh_string_data(pubkey)); if (key->dsa_pub == NULL) { goto error; } #elif defined HAVE_LIBCRYPTO key->dsa_pub = DSA_new(); if (key->dsa_pub == NULL) { goto error; } key->dsa_pub->p = make_string_bn(p); key->dsa_pub->q = make_string_bn(q); key->dsa_pub->g = make_string_bn(g); key->dsa_pub->pub_key = make_string_bn(pubkey); if (key->dsa_pub->p == NULL || key->dsa_pub->q == NULL || key->dsa_pub->g == NULL || key->dsa_pub->pub_key == NULL) { goto error; } #endif /* HAVE_LIBCRYPTO */ #ifdef DEBUG_CRYPTO ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p)); ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q)); ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g)); #endif ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); return key; error: ssh_string_burn(p); ssh_string_free(p); ssh_string_burn(q); ssh_string_free(q); ssh_string_burn(g); ssh_string_free(g); ssh_string_burn(pubkey); ssh_string_free(pubkey); publickey_free(key); return NULL; }
int ssh_pki_signature_verify_blob(ssh_session session, ssh_string sig_blob, const ssh_key key, unsigned char *digest, size_t dlen) { ssh_signature sig; int rc; rc = ssh_pki_import_signature_blob(sig_blob, key, &sig); if (rc < 0) { return SSH_ERROR; } SSH_LOG(SSH_LOG_FUNCTIONS, "Going to verify a %s type signature", key->type_c); if (key->type == SSH_KEYTYPE_ECDSA) { #if HAVE_ECC unsigned char ehash[EVP_DIGEST_LEN] = {0}; uint32_t elen; evp(key->ecdsa_nid, digest, dlen, ehash, &elen); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash to be verified with ecdsa", ehash, elen); #endif rc = pki_signature_verify(session, sig, key, ehash, elen); #endif } else if (key->type == SSH_KEYTYPE_ED25519) { rc = pki_signature_verify(session, sig, key, digest, dlen); } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; sha1(digest, dlen, hash); #ifdef DEBUG_CRYPTO ssh_print_hexa(key->type == SSH_KEYTYPE_DSS ? "Hash to be verified with DSA" : "Hash to be verified with RSA", hash, SHA_DIGEST_LEN); #endif rc = pki_signature_verify(session, sig, key, hash, SHA_DIGEST_LEN); } ssh_signature_free(sig); return rc; }
int ssh_packet_send1(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); uint32_t currentlen = ssh_buffer_get_len(session->out_buffer) + sizeof(uint32_t); char padstring[32] = {0}; int rc = SSH_ERROR; uint32_t finallen; uint32_t crc; uint8_t padding; SSH_LOG(SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen); /* TODO FIXME #ifdef WITH_ZLIB if (session->current_crypto && session->current_crypto->do_compress_out) { if (compress_buffer(session, session->out_buffer) < 0) { goto error; } currentlen = ssh_buffer_get_len(session->out_buffer); } #endif */ padding = blocksize - (currentlen % blocksize); if (session->current_crypto) { ssh_get_random(padstring, padding, 0); } else { memset(padstring, 0, padding); } finallen = htonl(currentlen); SSH_LOG(SSH_LOG_PACKET, "%d bytes after comp + %d padding bytes = %d bytes packet", currentlen, padding, ntohl(finallen)); if (ssh_buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) { goto error; } if (ssh_buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) { goto error; } crc = ssh_crc32((char *)ssh_buffer_get(session->out_buffer) + sizeof(uint32_t), ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t)); if (ssh_buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) { goto error; } #ifdef DEBUG_CRYPTO ssh_print_hexa("Clear packet", ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); #endif /* session->out_buffer should have more than sizeof(uint32_t) bytes in it as required for ssh_packet_encrypt */ ssh_packet_encrypt(session, (unsigned char *)ssh_buffer_get(session->out_buffer) + sizeof(uint32_t), ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t)); #ifdef DEBUG_CRYPTO ssh_print_hexa("encrypted packet",ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); #endif rc=ssh_socket_write(session->socket, ssh_buffer_get(session->out_buffer), ssh_buffer_get_len(session->out_buffer)); if(rc== SSH_ERROR) { goto error; } session->send_seq++; if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: return rc; /* SSH_OK, AGAIN or ERROR */ }
/* * This function signs the session id as a string then * the content of sigbuf */ ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, const ssh_key privkey) { struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto : session->next_crypto; ssh_signature sig = NULL; ssh_string sig_blob; ssh_string session_id; int rc; if (privkey == NULL || !ssh_key_is_private(privkey)) { return NULL; } session_id = ssh_string_new(crypto->digest_len); if (session_id == NULL) { return NULL; } ssh_string_fill(session_id, crypto->session_id, crypto->digest_len); if (privkey->type == SSH_KEYTYPE_ECDSA) { #ifdef HAVE_ECC unsigned char ehash[EVP_DIGEST_LEN] = {0}; uint32_t elen; EVPCTX ctx; ctx = evp_init(privkey->ecdsa_nid); if (ctx == NULL) { ssh_string_free(session_id); return NULL; } evp_update(ctx, session_id, ssh_string_len(session_id) + 4); evp_update(ctx, ssh_buffer_get(sigbuf), ssh_buffer_get_len(sigbuf)); evp_final(ctx, ehash, &elen); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", ehash, elen); #endif sig = pki_do_sign(privkey, ehash, elen); #endif } else if (privkey->type == SSH_KEYTYPE_ED25519){ ssh_buffer buf; buf = ssh_buffer_new(); if (buf == NULL) { ssh_string_free(session_id); return NULL; } ssh_buffer_set_secure(buf); rc = ssh_buffer_pack(buf, "SP", session_id, ssh_buffer_get_len(sigbuf), ssh_buffer_get(sigbuf)); if (rc != SSH_OK) { ssh_string_free(session_id); ssh_buffer_free(buf); return NULL; } sig = pki_do_sign(privkey, ssh_buffer_get(buf), ssh_buffer_get_len(buf)); ssh_buffer_free(buf); } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; SHACTX ctx; ctx = sha1_init(); if (ctx == NULL) { ssh_string_free(session_id); return NULL; } sha1_update(ctx, session_id, ssh_string_len(session_id) + 4); sha1_update(ctx, ssh_buffer_get(sigbuf), ssh_buffer_get_len(sigbuf)); sha1_final(hash, ctx); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); #endif sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN); } ssh_string_free(session_id); if (sig == NULL) { return NULL; } rc = ssh_pki_export_signature_blob(sig, &sig_blob); ssh_signature_free(sig); if (rc < 0) { return NULL; } return sig_blob; }