1
1

Add more error checks to signature_from_string().

git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@538 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Andreas Schneider 2009-04-18 09:33:32 +00:00
родитель 3df5a0dabe
Коммит 4308bb559c

Просмотреть файл

@ -849,141 +849,207 @@ static STRING *signature_to_string(SIGNATURE *sign) {
}
/* 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){
SIGNATURE *signature_from_string(SSH_SESSION *session, STRING *signature,
PUBLIC_KEY *pubkey, int needed_type) {
SIGNATURE *sign = NULL;
BUFFER *tmpbuf = NULL;
STRING *rs = NULL;
STRING *type_s = NULL;
STRING *e = NULL;
char *type = NULL;
int len;
int rsalen;
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t sig;
gcry_sexp_t sig;
#elif defined HAVE_LIBCRYPTO
DSA_SIG *sig;
STRING *r,*s;
DSA_SIG *sig = NULL;
STRING *r = NULL;
STRING *s = NULL;
#endif
SIGNATURE *sign;
BUFFER *tmpbuf;
STRING *rs;
STRING *type_s,*e;
int len,rsalen;
char *type;
sign = malloc(sizeof(SIGNATURE));
if (sign == NULL) {
ssh_set_error(session, SSH_FATAL, "No space left");
return NULL;
}
sign = malloc(sizeof(SIGNATURE));
if (sign == NULL) {
ssh_set_error(session, SSH_FATAL, "Not enough space");
return NULL;
}
tmpbuf = buffer_new();
if (tmpbuf == NULL) {
ssh_set_error(session, SSH_FATAL, "No space left");
signature_free(sign);
return NULL;
}
tmpbuf = buffer_new();
if (tmpbuf == NULL) {
ssh_set_error(session, SSH_FATAL, "Not enough space");
signature_free(sign);
return NULL;
}
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");
if (buffer_add_data(tmpbuf, signature->string, string_len(signature)) < 0) {
signature_free(sign);
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);
buffer_free(tmpbuf);
return NULL;
}
type = string_to_char(type_s);
free(type_s);
if (type == NULL) {
signature_free(sign);
buffer_free(tmpbuf);
return NULL;
}
switch(needed_type) {
case TYPE_DSS:
if (strcmp(type, "ssh-dss") != 0) {
ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s", type);
signature_free(sign);
buffer_free(tmpbuf);
SAFE_FREE(type);
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);
signature_free(sign);
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);
signature_free(sign);
buffer_free(tmpbuf);
free(type);
return NULL;
}
break;
default:
ssh_set_error(session,SSH_FATAL,"Invalid signature type : %s",type);
free(type);
signature_free(sign);
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);
signature_free(sign);
return NULL;
}
/* we make use of strings (because we have all-made functions to convert them to bignums (ou pas ;)*/
}
break;
case TYPE_RSA:
if (strcmp(type, "ssh-rsa")) {
ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s", type);
signature_free(sign);
buffer_free(tmpbuf);
SAFE_FREE(type);
return NULL;
}
break;
default:
ssh_set_error(session, SSH_FATAL, "Invalid signature type: %s", type);
signature_free(sign);
buffer_free(tmpbuf);
SAFE_FREE(type);
return NULL;
}
SAFE_FREE(type);
switch(needed_type) {
case TYPE_DSS:
rs = buffer_get_ssh_string(tmpbuf);
buffer_free(tmpbuf);
/* 40 is the dual signature blob len. */
if (rs == NULL || string_len(rs) != 40) {
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
gcry_sexp_build(&sig,NULL,"(sig-val(dsa(r %b)(s %b)))",20,rs->string,20,rs->string+20);
if (gcry_sexp_build(&sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
20 ,rs->string, 20, rs->string + 20)) {
string_free(rs);
signature_free(sign);
return NULL;
}
#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);
r = string_new(20);
s = string_new(20);
if (r == NULL || s == NULL) {
string_free(r);
string_free(s);
string_free(rs);
signature_free(sign);
return NULL;
}
string_fill(r, rs->string, 20);
string_fill(s, rs->string + 20, 20);
sig = DSA_SIG_new();
if (sig == NULL) {
string_free(r);
string_free(s);
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);
string_free(r);
string_free(s);
if (sig->r == NULL || sig->s == NULL) {
string_free(rs);
DSA_SIG_free(sig);
signature_free(sign);
return NULL;
}
#endif
#ifdef DEBUG_CRYPTO
ssh_print_hexa("r",rs->string,20);
ssh_print_hexa("s",rs->string+20,20);
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 == NULL) {
signature_free(sign);
return NULL;
}
len=string_len(e);
string_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 == NULL) {
signature_free(sign);
return NULL;
}
len = string_len(e);
#ifdef HAVE_LIBGCRYPT
rsalen=(gcry_pk_get_nbits(pubkey->rsa_pub)+7)/8;
rsalen = (gcry_pk_get_nbits(pubkey->rsa_pub) + 7) / 8;
#elif defined HAVE_LIBCRYPTO
rsalen=RSA_size(pubkey->rsa_pub);
rsalen = RSA_size(pubkey->rsa_pub);
#endif
if(len>rsalen){
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=TYPE_RSA;
if (len > rsalen) {
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 = TYPE_RSA;
#ifdef HAVE_LIBGCRYPT
gcry_sexp_build(&sig,NULL,"(sig-val(rsa(s %b)))",string_len(e),e->string);
sign->rsa_sign=sig;
if (gcry_sexp_build(&sig, NULL, "(sig-val(rsa(s %b)))",
string_len(e), e->string)) {
signature_free(sign);
string_free(e);
return NULL;
}
sign->rsa_sign = sig;
#elif defined HAVE_LIBCRYPTO
sign->rsa_sign=e;
sign->rsa_sign = e;
#endif
#ifdef DEBUG_CRYPTO
ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len);
ssh_print_hexa("rsa signature", e->string, len);
ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len);
ssh_print_hexa("RSA signature", e->string, len);
#endif
#ifdef HAVE_LIBGCRYPT
free(e);
string_free(e);
#endif
return sign;
default:
return NULL;
}
return sign;
default:
return NULL;
}
return NULL;
}
void signature_free(SIGNATURE *sign) {