/* Return the PK algorithm used by CERT as well as the length in bits of the public key at NBITS. */ int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) { gcry_sexp_t s_pkey; int rc; ksba_sexp_t p; size_t n; gcry_sexp_t l1, l2; const char *name; char namebuf[128]; if (nbits) *nbits = 0; p = ksba_cert_get_public_key (cert); if (!p) return 0; n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { xfree (p); return 0; } rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n); xfree (p); if (rc) return 0; if (nbits) *nbits = gcry_pk_get_nbits (s_pkey); /* Breaking the algorithm out of the S-exp is a bit of a challenge ... */ l1 = gcry_sexp_find_token (s_pkey, "public-key", 0); if (!l1) { gcry_sexp_release (s_pkey); return 0; } l2 = gcry_sexp_cadr (l1); gcry_sexp_release (l1); l1 = l2; name = gcry_sexp_nth_data (l1, 0, &n); if (name) { if (n > sizeof namebuf -1) n = sizeof namebuf -1; memcpy (namebuf, name, n); namebuf[n] = 0; } else *namebuf = 0; gcry_sexp_release (l1); gcry_sexp_release (s_pkey); return gcry_pk_map_name (namebuf); }
CK_RV gkm_rsa_mechanism_verify (gcry_sexp_t sexp, EggPadding padding, CK_BYTE_PTR data, CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG n_signature) { gcry_sexp_t ssig, sdata; gcry_error_t gcry; guint nbits; CK_RV rv; g_return_val_if_fail (sexp, CKR_GENERAL_ERROR); g_return_val_if_fail (signature, CKR_ARGUMENTS_BAD); g_return_val_if_fail (data, CKR_ARGUMENTS_BAD); /* The key size */ nbits = gcry_pk_get_nbits (sexp); g_return_val_if_fail (nbits > 0, CKR_GENERAL_ERROR); if (n_signature != (nbits + 7) / 8) return CKR_SIGNATURE_LEN_RANGE; /* Prepare the input s expressions */ rv = gkm_crypto_data_to_sexp ("(data (flags raw) (value %m))", nbits, padding, data, n_data, &sdata); if (rv != CKR_OK) return rv; rv = gkm_crypto_data_to_sexp ("(sig-val (rsa (s %m)))", nbits, NULL, signature, n_signature, &ssig); if (rv != CKR_OK) { gcry_sexp_release (sdata); return rv; } /* Do the magic */ gcry = gcry_pk_verify (ssig, sdata, sexp); gcry_sexp_release (sdata); gcry_sexp_release (ssig); /* TODO: See if any other codes should be mapped */ if (gcry_err_code (gcry) == GPG_ERR_BAD_SIGNATURE) { return CKR_SIGNATURE_INVALID; } else if (gcry) { g_message ("signing of the data failed: %s", gcry_strerror (gcry)); return CKR_FUNCTION_FAILED; } return CKR_OK; }
CK_RV gkm_rsa_mechanism_decrypt (gcry_sexp_t sexp, EggPadding padding, CK_BYTE_PTR encrypted, CK_ULONG n_encrypted, CK_BYTE_PTR data, CK_ULONG_PTR n_data) { gcry_sexp_t splain, sdata; gcry_error_t gcry; guint nbits; CK_RV rv; g_return_val_if_fail (sexp, CKR_GENERAL_ERROR); g_return_val_if_fail (n_data, CKR_ARGUMENTS_BAD); g_return_val_if_fail (encrypted, CKR_ARGUMENTS_BAD); nbits = gcry_pk_get_nbits (sexp); g_return_val_if_fail (nbits > 0, CKR_GENERAL_ERROR); /* Just want to know the length */ if (!data) { *n_data = (nbits + 7) / 8; return CKR_OK; } if (n_encrypted != (nbits + 7) / 8) return CKR_DATA_LEN_RANGE; /* Prepare the input s expression */ rv = gkm_crypto_data_to_sexp ("(enc-val (flags) (rsa (a %m)))", nbits, NULL, encrypted, n_encrypted, &sdata); if (rv != CKR_OK) return rv; /* Do the magic */ gcry = gcry_pk_decrypt (&splain, sdata, sexp); gcry_sexp_release (sdata); /* TODO: Certain codes should be returned (data too big etc... ) */ if (gcry) { g_message ("decrypting of the data failed: %s", gcry_strerror (gcry)); return CKR_FUNCTION_FAILED; } /* Now extract and send it back out */ rv = gkm_crypto_sexp_to_data (splain, nbits, data, n_data, padding, "value", NULL); gcry_sexp_release (splain); return rv; }
CK_RV gkm_rsa_mechanism_sign (gcry_sexp_t sexp, EggPadding padding, CK_BYTE_PTR data, CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG_PTR n_signature) { gcry_sexp_t ssig, sdata; guint nbits; gcry_error_t gcry; CK_RV rv; g_return_val_if_fail (sexp, CKR_GENERAL_ERROR); g_return_val_if_fail (n_signature, CKR_ARGUMENTS_BAD); g_return_val_if_fail (data, CKR_ARGUMENTS_BAD); nbits = gcry_pk_get_nbits (sexp); g_return_val_if_fail (nbits > 0, CKR_GENERAL_ERROR); /* Just want to know the length */ if (!signature) { *n_signature = (nbits + 7) / 8; return CKR_OK; } /* Prepare the input sexp */ rv = gkm_crypto_data_to_sexp ("(data (flags raw) (value %m))", nbits, padding, data, n_data, &sdata); if (rv != CKR_OK) return rv; /* Do the magic */ gcry = gcry_pk_sign (&ssig, sdata, sexp); gcry_sexp_release (sdata); /* TODO: Certain codes should be returned (data too big etc... ) */ if (gcry) { g_message ("signing of the data failed: %s", gcry_strerror (gcry)); return CKR_FUNCTION_FAILED; } /* Now extract and send it back out */ rv = gkm_crypto_sexp_to_data (ssig, nbits, signature, n_signature, NULL, "rsa", "s", NULL); gcry_sexp_release (ssig); return rv; }
void test_sexp ( int argc, char **argv ) { int rc, nbits; gcry_sexp_t sexp; gcry_mpi_t key[3]; size_t n; char *buf; if ( gcry_mpi_scan( &key[0], GCRYMPI_FMT_HEX, elg_testkey1.p, NULL ) ) BUG(); if ( gcry_mpi_scan( &key[1], GCRYMPI_FMT_HEX, elg_testkey1.g, NULL ) ) BUG(); if ( gcry_mpi_scan( &key[2], GCRYMPI_FMT_HEX, elg_testkey1.y, NULL ) ) BUG(); /* get nbits from a key */ rc = gcry_sexp_build ( &sexp, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", key[0], key[1], key[2] ); fputs ( "DUMP of PK:\n", stderr ); gcry_sexp_dump ( sexp ); { gcry_sexp_t x; x = gcry_sexp_cdr ( sexp ); fputs ( "DUMP of CDR:\n", stderr ); gcry_sexp_dump ( x ); gcry_sexp_release ( x ); } nbits = gcry_pk_get_nbits( sexp ); printf ( "elg_testkey1 - nbits=%d\n", nbits ); n = gcry_sexp_sprint ( sexp, 0, NULL, 0 ); buf = gcry_xmalloc ( n ); n = gcry_sexp_sprint ( sexp, 0, buf, n ); printf ( "sprint length=%u\n", (unsigned int)n ); gcry_free ( buf ); gcry_sexp_release( sexp ); }
/* 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; }
/* 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; } }
/** * @brief Write the current server as known in the known hosts file. * * This will create the known hosts file if it does not exist. You generaly use * it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN. * * @param[in] session The ssh session to use. * * @return SSH_OK on success, SSH_ERROR on error. */ int ssh_write_knownhost(ssh_session session) { ssh_string pubkey; unsigned char *pubkey_64; char buffer[4096] = {0}; FILE *file; char *dir; char *host; char *hostport; size_t len = 0; if (session->host == NULL) { ssh_set_error(session, SSH_FATAL, "Can't write host in known hosts if the hostname isn't known"); return SSH_ERROR; } host = ssh_lowercase(session->host); /* If using a nonstandard port, save the host in the [host]:port format */ if(session->port != 22){ hostport = ssh_hostport(host,session->port); SAFE_FREE(host); host=hostport; hostport=NULL; } if (session->knownhosts == NULL) { if (ssh_options_apply(session) < 0) { ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file"); return SSH_ERROR; } } if(session->current_crypto==NULL) { ssh_set_error(session, SSH_FATAL, "No current crypto context"); return SSH_ERROR; } pubkey = session->current_crypto->server_pubkey; if(pubkey == NULL){ ssh_set_error(session, SSH_FATAL, "No public key present"); return SSH_ERROR; } /* Check if ~/.ssh exists and create it if not */ dir = ssh_dirname(session->knownhosts); if (dir == NULL) { ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); return -1; } if (! ssh_file_readaccess_ok(dir)) { if (ssh_mkdir(dir, 0700) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot create %s directory.", dir); SAFE_FREE(dir); return -1; } } SAFE_FREE(dir); file = fopen(session->knownhosts, "a"); if (file == NULL) { ssh_set_error(session, SSH_FATAL, "Couldn't open known_hosts file %s for appending: %s", session->knownhosts, strerror(errno)); SAFE_FREE(host); return -1; } if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) { /* openssh uses a different format for ssh-rsa1 keys. Be compatible --kv */ ssh_public_key key; char *e_string = NULL; char *n_string = NULL; bignum e = NULL; bignum n = NULL; int rsa_size; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; #endif key = publickey_from_string(session, pubkey); if (key == NULL) { fclose(file); SAFE_FREE(host); return -1; } #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(key->rsa_pub, "e", 0); if (sexp == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (e == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } sexp = gcry_sexp_find_token(key->rsa_pub, "n", 0); if (sexp == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (n == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } rsa_size = (gcry_pk_get_nbits(key->rsa_pub) + 7) / 8; #elif defined HAVE_LIBCRYPTO e = key->rsa_pub->e; n = key->rsa_pub->n; rsa_size = RSA_size(key->rsa_pub); #endif e_string = bignum_bn2dec(e); n_string = bignum_bn2dec(n); if (e_string == NULL || n_string == NULL) { #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %d %s %s\n", host, rsa_size << 3, e_string, n_string); #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); } else { pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey)); if (pubkey_64 == NULL) { fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %s %s\n", host, session->current_crypto->server_pubkey_type, pubkey_64); SAFE_FREE(pubkey_64); } SAFE_FREE(host); len = strlen(buffer); if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) { fclose(file); return -1; } fclose(file); return 0; }
static int do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, gcry_sexp_t pkey, gcry_mpi_t *r_val) { int n; size_t nframe; unsigned char *frame; if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA) { unsigned int qbits; if ( pkalgo == GCRY_PK_ECDSA ) qbits = gcry_pk_get_nbits (pkey); else qbits = get_dsa_qbits (pkey); if ( (qbits%8) ) { log_error(_("DSA requires the hash length to be a" " multiple of 8 bits\n")); return gpg_error (GPG_ERR_INTERNAL); } /* Don't allow any Q smaller than 160 bits. We don't want someone to issue signatures from a key with a 16-bit Q or something like that, which would look correct but allow trivial forgeries. Yes, I know this rules out using MD5 with DSA. ;) */ if (qbits < 160) { log_error (_("%s key uses an unsafe (%u bit) hash\n"), gcry_pk_algo_name (pkalgo), qbits); return gpg_error (GPG_ERR_INTERNAL); } /* Check if we're too short. Too long is safe as we'll automatically left-truncate. */ nframe = gcry_md_get_algo_dlen (algo); if (nframe < qbits/8) { log_error (_("a %u bit hash is not valid for a %u bit %s key\n"), (unsigned int)nframe*8, gcry_pk_get_nbits (pkey), gcry_pk_algo_name (pkalgo)); /* FIXME: we need to check the requirements for ECDSA. */ if (nframe < 20 || pkalgo == GCRY_PK_DSA ) return gpg_error (GPG_ERR_INTERNAL); } frame = xtrymalloc (nframe); if (!frame) return out_of_core (); memcpy (frame, gcry_md_read (md, algo), nframe); n = nframe; /* Truncate. */ if (n > qbits/8) n = qbits/8; } else { int i; unsigned char asn[100]; size_t asnlen; size_t len; nframe = (nbits+7) / 8; asnlen = DIM(asn); if (!algo || gcry_md_test_algo (algo)) return gpg_error (GPG_ERR_DIGEST_ALGO); if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) { log_error ("no object identifier for algo %d\n", algo); return gpg_error (GPG_ERR_INTERNAL); } len = gcry_md_get_algo_dlen (algo); if ( len + asnlen + 4 > nframe ) { log_error ("can't encode a %d bit MD into a %d bits frame\n", (int)(len*8), (int)nbits); return gpg_error (GPG_ERR_INTERNAL); } /* We encode the MD in this way: * * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) * * PAD consists of FF bytes. */ frame = xtrymalloc (nframe); if (!frame) return out_of_core (); n = 0; frame[n++] = 0; frame[n++] = 1; /* block type */ i = nframe - len - asnlen -3 ; assert ( i > 1 ); memset ( frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy ( frame+n, asn, asnlen ); n += asnlen; memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len; assert ( n == nframe ); } if (DBG_CRYPTO) { int j; log_debug ("encoded hash:"); for (j=0; j < nframe; j++) log_printf (" %02X", frame[j]); log_printf ("\n"); } gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe); xfree (frame); return 0; }
int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, gcry_md_hd_t md, int mdalgo, int *r_pkalgo) { int rc; ksba_sexp_t p; gcry_mpi_t frame; gcry_sexp_t s_sig, s_hash, s_pkey; size_t n; int pkalgo; if (r_pkalgo) *r_pkalgo = 0; n = gcry_sexp_canon_len (sigval, 0, NULL, NULL); if (!n) { log_error ("libksba did not return a proper S-Exp\n"); return gpg_error (GPG_ERR_BUG); } rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); return rc; } p = ksba_cert_get_public_key (cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { log_error ("libksba did not return a proper S-Exp\n"); ksba_free (p); gcry_sexp_release (s_sig); return gpg_error (GPG_ERR_BUG); } if (DBG_CRYPTO) log_printhex ("public key: ", p, n); rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); gcry_sexp_release (s_sig); return rc; } pkalgo = pk_algo_from_sexp (s_pkey); if (r_pkalgo) *r_pkalgo = pkalgo; rc = do_encode_md (md, mdalgo, pkalgo, gcry_pk_get_nbits (s_pkey), s_pkey, &frame); if (rc) { gcry_sexp_release (s_sig); gcry_sexp_release (s_pkey); return rc; } /* put hash into the S-Exp s_hash */ if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) BUG (); gcry_mpi_release (frame); rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; }
/* Check the signature on CERT using the ISSUER-CERT. This function does only test the cryptographic signature and nothing else. It is assumed that the ISSUER_CERT is valid. */ int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) { const char *algoid; gcry_md_hd_t md; int rc, algo; gcry_mpi_t frame; ksba_sexp_t p; size_t n; gcry_sexp_t s_sig, s_hash, s_pkey; algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert))); if (!algo) { log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?"); if (algoid && ( !strcmp (algoid, "1.2.840.113549.1.1.2") ||!strcmp (algoid, "1.2.840.113549.2.2"))) log_info (_("(this is the MD2 algorithm)\n")); return gpg_error (GPG_ERR_GENERAL); } rc = gcry_md_open (&md, algo, 0); if (rc) { log_error ("md_open failed: %s\n", gpg_strerror (rc)); return rc; } if (DBG_HASHING) gcry_md_debug (md, "hash.cert"); rc = ksba_cert_hash (cert, 1, HASH_FNC, md); if (rc) { log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc)); gcry_md_close (md); return rc; } gcry_md_final (md); p = ksba_cert_get_sig_val (cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { log_error ("libksba did not return a proper S-Exp\n"); gcry_md_close (md); ksba_free (p); return gpg_error (GPG_ERR_BUG); } if (DBG_CRYPTO) { int j; log_debug ("signature value:"); for (j=0; j < n; j++) log_printf (" %02X", p[j]); log_printf ("\n"); } rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n); ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); gcry_md_close (md); return rc; } p = ksba_cert_get_public_key (issuer_cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { log_error ("libksba did not return a proper S-Exp\n"); gcry_md_close (md); ksba_free (p); gcry_sexp_release (s_sig); return gpg_error (GPG_ERR_BUG); } rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); gcry_md_close (md); gcry_sexp_release (s_sig); return rc; } rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey), gcry_pk_get_nbits (s_pkey), s_pkey, &frame); if (rc) { gcry_md_close (md); gcry_sexp_release (s_sig); gcry_sexp_release (s_pkey); return rc; } /* put hash into the S-Exp s_hash */ if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) BUG (); gcry_mpi_release (frame); rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_md_close (md); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; }