bool ans_key_h(connection_t *c) { char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; char key[MAX_STRING_SIZE]; char address[MAX_STRING_SIZE] = ""; char port[MAX_STRING_SIZE] = ""; int cipher, digest, maclength, compression; node_t *from, *to; if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, from_name, to_name, key, &cipher, &digest, &maclength, &compression, address, port) < 7) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, c->hostname); return false; } if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name"); return false; } from = lookup_node(from_name); if(!from) { logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "ANS_KEY", c->name, c->hostname, from_name); return true; } to = lookup_node(to_name); if(!to) { logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "ANS_KEY", c->name, c->hostname, to_name); return true; } /* Forward it if necessary */ if(to != myself) { if(tunnelserver) return true; if(!to->status.reachable) { logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", "ANS_KEY", c->name, c->hostname, to_name); return true; } if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) { char *address, *port; ifdebug(PROTOCOL) logger(LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name); sockaddr2str(&from->address, &address, &port); send_request(to->nexthop->connection, "%s %s %s", c->buffer, address, port); free(address); free(port); return true; } return send_request(to->nexthop->connection, "%s", c->buffer); } /* Don't use key material until every check has passed. */ from->status.validkey = false; /* Update our copy of the origin's packet key */ from->outkey = xrealloc(from->outkey, strlen(key) / 2); from->outkeylength = strlen(key) / 2; if(!hex2bin(key, from->outkey, from->outkeylength)) { logger(LOG_ERR, "Got bad %s from %s(%s): %s", "ANS_KEY", from->name, from->hostname, "invalid key"); return true; } /* Check and lookup cipher and digest algorithms */ if(cipher) { from->outcipher = EVP_get_cipherbynid(cipher); if(!from->outcipher) { logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname); return true; } if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) { logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname); return true; } } else { from->outcipher = NULL; } from->outmaclength = maclength; if(digest) { from->outdigest = EVP_get_digestbynid(digest); if(!from->outdigest) { logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname); return true; } if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) { logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname); return true; } } else { from->outdigest = NULL; } if(compression < 0 || compression > 11) { logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname); return true; } from->outcompression = compression; if(from->outcipher) if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) { logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s", from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL)); return true; } from->status.validkey = true; from->sent_seqno = 0; if(*address && *port) { ifdebug(PROTOCOL) logger(LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port); sockaddr_t sa = str2sockaddr(address, port); update_node_udp(from, &sa); } if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent) send_mtu_probe(from); return true; }
int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey, const EVP_MD *type) { EVP_MD_CTX ctx; unsigned char *buf_in=NULL,*buf_out=NULL; int inl=0,outl=0,outll=0; int signid, paramtype; if (type == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0) type = EVP_get_digestbynid(def_nid); } if (type == NULL) { ASN1err(ASN1_F_ASN1_ITEM_SIGN, ASN1_R_NO_DEFAULT_DIGEST); return 0; } if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { if (!pkey->ameth || !OBJ_find_sigid_by_algs(&signid, EVP_MD_nid(type), pkey->ameth->pkey_id)) { ASN1err(ASN1_F_ASN1_ITEM_SIGN, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); return 0; } } else signid = type->pkey_type; if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) paramtype = V_ASN1_NULL; else paramtype = V_ASN1_UNDEF; if (algor1) X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL); if (algor2) X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL); EVP_MD_CTX_init(&ctx); inl=ASN1_item_i2d((ASN1_VALUE*)asn,&buf_in, it); //MS: cast to match signature outll=outl=EVP_PKEY_size(pkey); buf_out=(unsigned char *)OPENSSL_malloc((unsigned int)outl); if ((buf_in == NULL) || (buf_out == NULL)) { outl=0; ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_MALLOC_FAILURE); goto err; } EVP_SignInit_ex(&ctx,type, NULL); EVP_SignUpdate(&ctx,(unsigned char *)buf_in,inl); if (!EVP_SignFinal(&ctx,(unsigned char *)buf_out, (unsigned int *)&outl,pkey)) { outl=0; ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_EVP_LIB); goto err; } if (signature->data != NULL) OPENSSL_free(signature->data); signature->data=buf_out; buf_out=NULL; signature->length=outl; /* In the interests of compatibility, I'll make sure that * the bit string has a 'not-used bits' value of 0 */ signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); signature->flags|=ASN1_STRING_FLAG_BITS_LEFT; err: EVP_MD_CTX_cleanup(&ctx); if (buf_in != NULL) { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); } if (buf_out != NULL) { OPENSSL_cleanse((char *)buf_out,outll); OPENSSL_free(buf_out); } return(outl); }
/*- * This function hijacks the RNG to feed it the chosen ECDSA key and nonce. * The ECDSA KATs are from: * - the X9.62 draft (4) * - NIST CAVP (720) * * It uses the low-level ECDSA_sign_setup instead of EVP to control the RNG. * NB: This is not how applications should use ECDSA; this is only for testing. * * Tests the library can successfully: * - generate public keys that matches those KATs * - create ECDSA signatures that match those KATs * - accept those signatures as valid */ static int x9_62_tests(int n) { int nid, md_nid, ret = 0; const char *r_in = NULL, *s_in = NULL, *tbs = NULL; unsigned char *pbuf = NULL, *qbuf = NULL, *message = NULL; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int dgst_len = 0; long q_len, msg_len = 0; size_t p_len; EVP_MD_CTX *mctx = NULL; EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; const BIGNUM *sig_r = NULL, *sig_s = NULL; nid = ecdsa_cavs_kats[n].nid; md_nid = ecdsa_cavs_kats[n].md_nid; r_in = ecdsa_cavs_kats[n].r; s_in = ecdsa_cavs_kats[n].s; tbs = ecdsa_cavs_kats[n].msg; numbers[0] = ecdsa_cavs_kats[n].d; numbers[1] = ecdsa_cavs_kats[n].k; TEST_info("ECDSA KATs for curve %s", OBJ_nid2sn(nid)); if (!TEST_ptr(mctx = EVP_MD_CTX_new()) /* get the message digest */ || !TEST_ptr(message = OPENSSL_hexstr2buf(tbs, &msg_len)) || !TEST_true(EVP_DigestInit_ex(mctx, EVP_get_digestbynid(md_nid), NULL)) || !TEST_true(EVP_DigestUpdate(mctx, message, msg_len)) || !TEST_true(EVP_DigestFinal_ex(mctx, digest, &dgst_len)) /* create the key */ || !TEST_ptr(key = EC_KEY_new_by_curve_name(nid)) /* load KAT variables */ || !TEST_ptr(r = BN_new()) || !TEST_ptr(s = BN_new()) || !TEST_true(BN_hex2bn(&r, r_in)) || !TEST_true(BN_hex2bn(&s, s_in)) /* swap the RNG source */ || !TEST_true(change_rand())) goto err; /* public key must match KAT */ use_fake = 1; if (!TEST_true(EC_KEY_generate_key(key)) || !TEST_true(p_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &pbuf, NULL)) || !TEST_ptr(qbuf = OPENSSL_hexstr2buf(ecdsa_cavs_kats[n].Q, &q_len)) || !TEST_int_eq(q_len, p_len) || !TEST_mem_eq(qbuf, q_len, pbuf, p_len)) goto err; /* create the signature via ECDSA_sign_setup to avoid use of ECDSA nonces */ use_fake = 1; if (!TEST_true(ECDSA_sign_setup(key, NULL, &kinv, &rp)) || !TEST_ptr(signature = ECDSA_do_sign_ex(digest, dgst_len, kinv, rp, key)) /* verify the signature */ || !TEST_int_eq(ECDSA_do_verify(digest, dgst_len, signature, key), 1)) goto err; /* compare the created signature with the expected signature */ ECDSA_SIG_get0(signature, &sig_r, &sig_s); if (!TEST_BN_eq(sig_r, r) || !TEST_BN_eq(sig_s, s)) goto err; ret = 1; err: /* restore the RNG source */ if (!TEST_true(restore_rand())) ret = 0; OPENSSL_free(message); OPENSSL_free(pbuf); OPENSSL_free(qbuf); EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(mctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) { CMS_SignedData *sd; CMS_SignerInfo *si = NULL; X509_ALGOR *alg; int i, type; if(!X509_check_private_key(signer, pk)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); return NULL; } sd = cms_signed_data_init(cms); if (!sd) goto err; si = M_ASN1_new_of(CMS_SignerInfo); if (!si) goto merr; X509_check_purpose(signer, -1, -1); CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY); CRYPTO_add(&signer->references, 1, CRYPTO_LOCK_X509); si->pkey = pk; si->signer = signer; if (flags & CMS_USE_KEYID) { si->version = 3; if (sd->version < 3) sd->version = 3; type = CMS_SIGNERINFO_KEYIDENTIFIER; } else { type = CMS_SIGNERINFO_ISSUER_SERIAL; si->version = 1; } if (!cms_set1_SignerIdentifier(si->sid, signer, type)) goto err; if (md == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) goto err; md = EVP_get_digestbynid(def_nid); if (md == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST); goto err; } } if (!md) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET); goto err; } cms_DigestAlgorithm_set(si->digestAlgorithm, md); /* See if digest is present in digestAlgorithms */ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) { ASN1_OBJECT *aoid; alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); X509_ALGOR_get0(&aoid, NULL, NULL, alg); if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) break; } if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) { alg = X509_ALGOR_new(); if (!alg) goto merr; cms_DigestAlgorithm_set(alg, md); if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) { X509_ALGOR_free(alg); goto merr; } } if (pk->ameth && pk->ameth->pkey_ctrl) { i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_SIGN, 0, si); if (i == -2) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); goto err; } if (i <= 0) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_CTRL_FAILURE); goto err; } } if (!(flags & CMS_NOATTR)) { /* Initialialize signed attributes strutucture so other * attributes such as signing time etc are added later * even if we add none here. */ if (!si->signedAttrs) { si->signedAttrs = sk_X509_ATTRIBUTE_new_null(); if (!si->signedAttrs) goto merr; } if (!(flags & CMS_NOSMIMECAP)) { STACK_OF(X509_ALGOR) *smcap = NULL; i = CMS_add_standard_smimecap(&smcap); if (i) i = CMS_add_smimecap(si, smcap); sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); if (!i) goto merr; } if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; if (!(flags & CMS_PARTIAL) && !CMS_SignerInfo_sign(si)) goto err; } } if (!(flags & CMS_NOCERTS)) { /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) goto merr; } if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) goto merr; return si; merr: CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); err: if (si) M_ASN1_free_of(si, CMS_SignerInfo); return NULL; }
int ssh_rsa_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, u_int compat) { struct sshbuf *b = NULL; const EVP_MD *evp_md; EVP_MD_CTX md; char *ktype; u_char digest[EVP_MAX_MD_SIZE], *osigblob, *sigblob = NULL; size_t len, diff, modlen; u_int dlen; int nid, ret = SSH_ERR_INTERNAL_ERROR; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00) || BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_INVALID_ARGUMENT; if ((b = sshbuf_from(signature, signaturelen)) == NULL) return SSH_ERR_ALLOC_FAIL; if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (strcmp("ssh-rsa", ktype) != 0) { ret = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (sshbuf_get_string(b, &sigblob, &len) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (sshbuf_len(b) != 0) { ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; goto out; } /* RSA_verify expects a signature of RSA_size */ modlen = RSA_size(key->rsa); if (len > modlen) { ret = SSH_ERR_KEY_BITS_MISMATCH; goto out; } else if (len < modlen) { diff = modlen - len; osigblob = sigblob; if ((sigblob = realloc(sigblob, modlen)) == NULL) { free(osigblob); ret = SSH_ERR_ALLOC_FAIL; goto out; } memmove(sigblob + diff, sigblob, len); memset(sigblob, 0, diff); len = modlen; } nid = (compat & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (EVP_DigestInit(&md, evp_md) != 1 || EVP_DigestUpdate(&md, data, datalen) != 1 || EVP_DigestFinal(&md, digest, &dlen) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); out: if (sigblob != NULL) { memset(sigblob, 's', len); free(sigblob); } if (ktype != NULL) free(ktype); if (b != NULL) sshbuf_free(b); bzero(digest, sizeof(digest)); bzero(&md, sizeof(md)); return ret; }
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) { EVP_MD_CTX ctx; unsigned char *buf_in = NULL; int ret = -1, inl; int mdnid, pknid; if (!pkey) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER); return -1; } EVP_MD_CTX_init(&ctx); /* Convert signature OID into digest and public key OIDs */ if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } if (mdnid == NID_undef) { if (!pkey->ameth || !pkey->ameth->item_verify) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } ret = pkey->ameth->item_verify(&ctx, it, asn, a, signature, pkey); /* Return value of 2 means carry on, anything else means we * exit straight away: either a fatal error of the underlying * verification routine handles all verification. */ if (ret != 2) goto err; ret = -1; } else { const EVP_MD *type; type = EVP_get_digestbynid(mdnid); if (type == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); goto err; } /* Check public key OID matches public key type */ if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_WRONG_PUBLIC_KEY_TYPE); goto err; } if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); ret = 0; goto err; } } inl = ASN1_item_i2d(asn, &buf_in, it); if (buf_in == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE); goto err; } if (!EVP_DigestVerifyUpdate(&ctx, buf_in, inl)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); ret = 0; goto err; } OPENSSL_cleanse(buf_in, (unsigned int)inl); free(buf_in); if (EVP_DigestVerifyFinal(&ctx, signature->data, (size_t)signature->length) <= 0) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); ret = 0; goto err; } /* we don't need to zero the 'ctx' because we just checked * public information */ /* memset(&ctx,0,sizeof(ctx)); */ ret = 1; err: EVP_MD_CTX_cleanup(&ctx); return (ret); }
int ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { Buffer b; const EVP_MD *evp_md; EVP_MD_CTX md; char *ktype; u_char *sigblob; u_int len, modlen; #ifdef USE_LEGACY_RSA_VERIFY u_char digest[EVP_MAX_MD_SIZE]; u_int dlen; #endif int rlen, ret, nid; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { error("ssh_rsa_verify: no RSA key"); return -1; } if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); return -1; } buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_cstring(&b, NULL); if (strcmp("ssh-rsa", ktype) != 0) { error("ssh_rsa_verify: cannot handle type %s", ktype); buffer_free(&b); xfree(ktype); return -1; } xfree(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("ssh_rsa_verify: remaining bytes in signature %d", rlen); xfree(sigblob); return -1; } /* RSA_verify expects a signature of RSA_size */ modlen = RSA_size(key->rsa); if (len > modlen) { error("ssh_rsa_verify: len %u > modlen %u", len, modlen); xfree(sigblob); return -1; } else if (len < modlen) { u_int diff = modlen - len; debug("ssh_rsa_verify: add padding: modlen %u > len %u", modlen, len); sigblob = xrealloc(sigblob, 1, modlen); memmove(sigblob + diff, sigblob, len); memset(sigblob, 0, diff); len = modlen; } nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); xfree(sigblob); return -1; } #ifdef USE_LEGACY_RSA_VERIFY 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->rsa); memset(digest, 'd', sizeof(digest)); #else /*ndef USE_LEGACY_RSA_VERIFY*/ { EVP_PKEY *pkey; ret = -1; pkey = EVP_PKEY_new(); if (pkey == NULL) { error("%s: out of memory", __func__); goto done; } EVP_PKEY_set1_RSA(pkey, key->rsa); ssh_EVP_MD_CTX_init(&md); ret = ssh_EVP_VerifyInit(&md, evp_md); if (ret <= 0) { char ebuf[256]; error("%s: EVP_VerifyInit fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } ret = ssh_EVP_VerifyUpdate(&md, data, datalen); if (ret <= 0) { char ebuf[256]; error("%s: EVP_VerifyUpdate fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } ret = EVP_VerifyFinal(&md, sigblob, len, pkey); if (ret <= 0) { char ebuf[256]; error("%s: EVP_VerifyFinal fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } clean: ssh_EVP_MD_CTX_cleanup(&md); done: if (pkey != NULL) EVP_PKEY_free(pkey); } #endif /*ndef USE_LEGACY_RSA_VERIFY*/ memset(sigblob, 's', len); xfree(sigblob); debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); return ret; }
/* * authreadkeys - (re)read keys from a file. */ int authreadkeys( const char *file ) { FILE *fp; char *line; char *token; keyid_t keyno; int keytype; char buf[512]; /* lots of room for line */ u_char keystr[32]; /* Bug 2537 */ size_t len; size_t j; u_int nerr; KeyDataT *list = NULL; KeyDataT *next = NULL; /* * Open file. Complain and return if it can't be opened. */ fp = fopen(file, "r"); if (fp == NULL) { msyslog(LOG_ERR, "authreadkeys: file '%s': %m", file); goto onerror; } INIT_SSL(); /* * Now read lines from the file, looking for key entries. Put * the data into temporary store for later propagation to avoid * two-pass processing. */ nerr = 0; while ((line = fgets(buf, sizeof buf, fp)) != NULL) { if (nerr > nerr_maxlimit) break; token = nexttok(&line); if (token == NULL) continue; /* * First is key number. See if it is okay. */ keyno = atoi(token); if (keyno < 1) { log_maybe(&nerr, "authreadkeys: cannot change key %s", token); continue; } if (keyno > NTP_MAXKEY) { log_maybe(&nerr, "authreadkeys: key %s > %d reserved for Autokey", token, NTP_MAXKEY); continue; } /* * Next is keytype. See if that is all right. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key type for key %d", keyno); continue; } /* We want to silently ignore keys where we do not * support the requested digest type. OTOH, we want to * make sure the file is well-formed. That means we * have to process the line completely and have to * finally throw away the result... This is a bit more * work, but it also results in better error detection. */ #ifdef OPENSSL /* * The key type is the NID used by the message digest * algorithm. There are a number of inconsistencies in * the OpenSSL database. We attempt to discover them * here and prevent use of inconsistent data later. */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { log_maybe(NULL, "authreadkeys: invalid type for key %d", keyno); } else if (EVP_get_digestbynid(keytype) == NULL) { log_maybe(NULL, "authreadkeys: no algorithm for key %d", keyno); keytype = 0; } #else /* !OPENSSL follows */ /* * The key type is unused, but is required to be 'M' or * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { log_maybe(NULL, "authreadkeys: invalid type for key %d", keyno); keytype = 0; } else { keytype = KEY_TYPE_MD5; } #endif /* !OPENSSL */ /* * Finally, get key and insert it. If it is longer than 20 * characters, it is a binary string encoded in hex; * otherwise, it is a text string of printable ASCII * characters. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key for key %d", keyno); continue; } next = NULL; len = strlen(token); if (len <= 20) { /* Bug 2537 */ next = emalloc(sizeof(KeyDataT) + len); next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; memcpy(next->secbuf, token, len); } else { static const char hex[] = "0123456789abcdef"; u_char temp; char *ptr; size_t jlim; jlim = min(len, 2 * sizeof(keystr)); for (j = 0; j < jlim; j++) { ptr = strchr(hex, tolower((unsigned char)token[j])); if (ptr == NULL) break; /* abort decoding */ temp = (u_char)(ptr - hex); if (j & 1) keystr[j / 2] |= temp; else keystr[j / 2] = temp << 4; } if (j < jlim) { log_maybe(&nerr, "authreadkeys: invalid hex digit for key %d", keyno); continue; } len = jlim/2; /* hmmmm.... what about odd length?!? */ next = emalloc(sizeof(KeyDataT) + len); next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; memcpy(next->secbuf, keystr, len); } token = nexttok(&line); DPRINTF(0, ("authreadkeys: full access list <%s>\n", (token) ? token : "NULL")); if (token != NULL) { /* A comma-separated IP access list */ char *tp = token; while (tp) { char *i; sockaddr_u addr; i = strchr(tp, (int)','); if (i) *i = '\0'; DPRINTF(0, ("authreadkeys: access list: <%s>\n", tp)); if (is_ip_address(tp, AF_UNSPEC, &addr)) { next->keyacclist = keyacc_new_push( next->keyacclist, &addr); } else { log_maybe(&nerr, "authreadkeys: invalid IP address <%s> for key %d", tp, keyno); } if (i) { tp = i + 1; } else { tp = 0; } } } /* check if this has to be weeded out... */ if (0 == keytype) { free_keydata(next); next = NULL; continue; } INSIST(NULL != next); next->next = list; list = next; } fclose(fp); if (nerr > 0) { const char * why = ""; if (nerr > nerr_maxlimit) why = " (emergency break)"; msyslog(LOG_ERR, "authreadkeys: rejecting file '%s' after %u error(s)%s", file, nerr, why); goto onerror; } /* first remove old file-based keys */ auth_delkeys(); /* insert the new key material */ while (NULL != (next = list)) { list = next->next; MD5auth_setkey(next->keyid, next->keytype, next->secbuf, next->seclen, next->keyacclist); next->keyacclist = NULL; /* consumed by MD5auth_setkey */ free_keydata(next); } return (1); onerror: /* Mop up temporary storage before bailing out. */ while (NULL != (next = list)) { list = next->next; free_keydata(next); } return (0); }
int int_rsa_verify(int dtype, const uint8_t *m, unsigned int m_len, uint8_t *rm, size_t *prm_len, const uint8_t *sigbuf, size_t siglen, RSA *rsa) { int i, ret = 0, sigtype; uint8_t *s; X509_SIG *sig = NULL; if (siglen != (unsigned int)RSA_size(rsa)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_WRONG_SIGNATURE_LENGTH); return (0); } if ((dtype == NID_md5_sha1) && rm) { i = RSA_public_decrypt((int)siglen, sigbuf, rm, rsa, RSA_PKCS1_PADDING); if (i <= 0) return 0; *prm_len = i; return 1; } s = malloc((unsigned int)siglen); if (s == NULL) { RSAerr(RSA_F_INT_RSA_VERIFY, ERR_R_MALLOC_FAILURE); goto err; } if ((dtype == NID_md5_sha1) && (m_len != SSL_SIG_LENGTH)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_MESSAGE_LENGTH); goto err; } i = RSA_public_decrypt((int)siglen, sigbuf, s, rsa, RSA_PKCS1_PADDING); if (i <= 0) goto err; /* Special case: SSL signature */ if (dtype == NID_md5_sha1) { if ((i != SSL_SIG_LENGTH) || memcmp(s, m, SSL_SIG_LENGTH)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); else ret = 1; } else { const uint8_t *p = s; sig = d2i_X509_SIG(NULL, &p, (long)i); if (sig == NULL) goto err; /* Excess data can be used to create forgeries */ if (p != s + i || !rsa_check_digestinfo(sig, s, i)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); goto err; } /* Parameters to the signature algorithm can also be used to create forgeries */ if (sig->algor->parameter && ASN1_TYPE_get(sig->algor->parameter) != V_ASN1_NULL) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); goto err; } sigtype = OBJ_obj2nid(sig->algor->algorithm); if (sigtype != dtype) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_ALGORITHM_MISMATCH); goto err; } if (rm) { const EVP_MD *md; md = EVP_get_digestbynid(dtype); if (md && (EVP_MD_size(md) != sig->digest->length)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH); else { memcpy(rm, sig->digest->data, sig->digest->length); *prm_len = sig->digest->length; ret = 1; } } else if (((unsigned int)sig->digest->length != m_len) || (memcmp(m, sig->digest->data, m_len) != 0)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); } else ret = 1; } err: X509_SIG_free(sig); if (s != NULL) { vigortls_zeroize(s, (unsigned int)siglen); free(s); } return (ret); }
bool metakey_h(connection_t *c) { char buffer[MAX_STRING_SIZE]; int cipher, digest, maclength, compression; int len; if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) { logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, c->hostname); return false; } len = RSA_size(myself->connection->rsa_key); /* Check if the length of the meta key is all right */ if(strlen(buffer) != (size_t)len * 2) { logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength"); return false; } /* Allocate buffers for the meta key */ c->inkey = xrealloc(c->inkey, len); if(!c->inctx) { c->inctx = EVP_CIPHER_CTX_new(); if(!c->inctx) { abort(); } } /* Convert the challenge from hexadecimal back to binary */ if(!hex2bin(buffer, buffer, len)) { logger(LOG_ERR, "Got bad %s from %s(%s): %s", "METAKEY", c->name, c->hostname, "invalid key"); return false; } /* Decrypt the meta key */ if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s", c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } ifdebug(SCARY_THINGS) { bin2hex(c->inkey, buffer, len); buffer[len * 2] = '\0'; logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", buffer); } /* All incoming requests will now be encrypted. */ /* Check and lookup cipher and digest algorithms */ if(cipher) { c->incipher = EVP_get_cipherbynid(cipher); if(!c->incipher) { logger(LOG_ERR, "%s (%s) uses unknown cipher!", c->name, c->hostname); return false; } if(!EVP_DecryptInit(c->inctx, c->incipher, (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher), (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher) - EVP_CIPHER_iv_length(c->incipher))) { logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s", c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; } c->inbudget = byte_budget(c->incipher); c->status.decryptin = true; } else { logger(LOG_ERR, "%s (%s) uses null cipher!", c->name, c->hostname); return false; } c->inmaclength = maclength; if(digest) { c->indigest = EVP_get_digestbynid(digest); if(!c->indigest) { logger(LOG_ERR, "Node %s (%s) uses unknown digest!", c->name, c->hostname); return false; } if(c->inmaclength > EVP_MD_size(c->indigest) || c->inmaclength < 0) { logger(LOG_ERR, "%s (%s) uses bogus MAC length!", c->name, c->hostname); return false; } } else { logger(LOG_ERR, "%s (%s) uses null digest!", c->name, c->hostname); return false; } c->incompression = compression; c->allow_request = CHALLENGE; return send_challenge(c); }
/* * authreadkeys - (re)read keys from a file. */ int authreadkeys( const char *file ) { FILE *fp; char *line; char *token; keyid_t keyno; int keytype; char buf[512]; /* lots of room for line */ u_char keystr[32]; /* Bug 2537 */ size_t len; size_t j; size_t nerr; /* * Open file. Complain and return if it can't be opened. */ fp = fopen(file, "r"); if (fp == NULL) { msyslog(LOG_ERR, "authreadkeys: file %s: %m", file); return (0); } INIT_SSL(); /* * Remove all existing keys */ auth_delkeys(); /* * Now read lines from the file, looking for key entries */ nerr = 0; while ((line = fgets(buf, sizeof buf, fp)) != NULL) { if (nerr > nerr_maxlimit) break; token = nexttok(&line); if (token == NULL) continue; /* * First is key number. See if it is okay. */ keyno = atoi(token); if (keyno == 0) { log_maybe(&nerr, "authreadkeys: cannot change key %s", token); continue; } if (keyno > NTP_MAXKEY) { log_maybe(&nerr, "authreadkeys: key %s > %d reserved for Autokey", token, NTP_MAXKEY); continue; } /* * Next is keytype. See if that is all right. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key type for key %d", keyno); continue; } #ifdef OPENSSL /* * The key type is the NID used by the message digest * algorithm. There are a number of inconsistencies in * the OpenSSL database. We attempt to discover them * here and prevent use of inconsistent data later. */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { log_maybe(&nerr, "authreadkeys: invalid type for key %d", keyno); continue; } if (EVP_get_digestbynid(keytype) == NULL) { log_maybe(&nerr, "authreadkeys: no algorithm for key %d", keyno); continue; } #else /* !OPENSSL follows */ /* * The key type is unused, but is required to be 'M' or * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { log_maybe(&nerr, "authreadkeys: invalid type for key %d", keyno); continue; } keytype = KEY_TYPE_MD5; #endif /* !OPENSSL */ /* * Finally, get key and insert it. If it is longer than 20 * characters, it is a binary string encoded in hex; * otherwise, it is a text string of printable ASCII * characters. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key for key %d", keyno); continue; } len = strlen(token); if (len <= 20) { /* Bug 2537 */ MD5auth_setkey(keyno, keytype, (u_char *)token, len); } else { char hex[] = "0123456789abcdef"; u_char temp; char *ptr; size_t jlim; jlim = min(len, 2 * sizeof(keystr)); for (j = 0; j < jlim; j++) { ptr = strchr(hex, tolower((unsigned char)token[j])); if (ptr == NULL) break; /* abort decoding */ temp = (u_char)(ptr - hex); if (j & 1) keystr[j / 2] |= temp; else keystr[j / 2] = temp << 4; } if (j < jlim) { log_maybe(&nerr, "authreadkeys: invalid hex digit for key %d", keyno); continue; } MD5auth_setkey(keyno, keytype, keystr, jlim / 2); } } fclose(fp); if (nerr > nerr_maxlimit) { msyslog(LOG_ERR, "authreadkeys: emergency break after %zu errors", nerr); return (0); } else if (nerr > nerr_loglimit) { msyslog(LOG_ERR, "authreadkeys: found %zu more error(s)", nerr - nerr_loglimit); } return (1); }
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, X509 *signer, EVP_PKEY *pk, const EVP_MD *md, unsigned int flags) { CMS_SignedData *sd; CMS_SignerInfo *si = NULL; X509_ALGOR *alg; int i, type; if (!X509_check_private_key(signer, pk)) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); return NULL; } sd = cms_signed_data_init(cms); if (!sd) goto err; si = M_ASN1_new_of(CMS_SignerInfo); if (!si) goto merr; /* Call for side-effect of computing hash and caching extensions */ X509_check_purpose(signer, -1, -1); X509_up_ref(signer); EVP_PKEY_up_ref(pk); si->pkey = pk; si->signer = signer; si->mctx = EVP_MD_CTX_new(); si->pctx = NULL; if (si->mctx == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); goto err; } if (flags & CMS_USE_KEYID) { si->version = 3; if (sd->version < 3) sd->version = 3; type = CMS_SIGNERINFO_KEYIDENTIFIER; } else { type = CMS_SIGNERINFO_ISSUER_SERIAL; si->version = 1; } if (!cms_set1_SignerIdentifier(si->sid, signer, type)) goto err; if (md == NULL) { int def_nid; if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) goto err; md = EVP_get_digestbynid(def_nid); if (md == NULL) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DEFAULT_DIGEST); goto err; } } if (!md) { CMSerr(CMS_F_CMS_ADD1_SIGNER, CMS_R_NO_DIGEST_SET); goto err; } X509_ALGOR_set_md(si->digestAlgorithm, md); /* See if digest is present in digestAlgorithms */ for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) { const ASN1_OBJECT *aoid; alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i); X509_ALGOR_get0(&aoid, NULL, NULL, alg); if (OBJ_obj2nid(aoid) == EVP_MD_type(md)) break; } if (i == sk_X509_ALGOR_num(sd->digestAlgorithms)) { alg = X509_ALGOR_new(); if (alg == NULL) goto merr; X509_ALGOR_set_md(alg, md); if (!sk_X509_ALGOR_push(sd->digestAlgorithms, alg)) { X509_ALGOR_free(alg); goto merr; } } if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) goto err; if (!(flags & CMS_NOATTR)) { /* * Initialize signed attributes structure so other attributes * such as signing time etc are added later even if we add none here. */ if (!si->signedAttrs) { si->signedAttrs = sk_X509_ATTRIBUTE_new_null(); if (!si->signedAttrs) goto merr; } if (!(flags & CMS_NOSMIMECAP)) { STACK_OF(X509_ALGOR) *smcap = NULL; i = CMS_add_standard_smimecap(&smcap); if (i) i = CMS_add_smimecap(si, smcap); sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free); if (!i) goto merr; } if (flags & CMS_REUSE_DIGEST) { if (!cms_copy_messageDigest(cms, si)) goto err; if (!(flags & (CMS_PARTIAL | CMS_KEY_PARAM)) && !CMS_SignerInfo_sign(si)) goto err; } } if (!(flags & CMS_NOCERTS)) { /* NB ignore -1 return for duplicate cert */ if (!CMS_add1_cert(cms, signer)) goto merr; } if (flags & CMS_KEY_PARAM) { if (flags & CMS_NOATTR) { si->pctx = EVP_PKEY_CTX_new(si->pkey, NULL); if (si->pctx == NULL) goto err; if (EVP_PKEY_sign_init(si->pctx) <= 0) goto err; if (EVP_PKEY_CTX_set_signature_md(si->pctx, md) <= 0) goto err; } else if (EVP_DigestSignInit(si->mctx, &si->pctx, md, NULL, pk) <= 0) goto err; } if (!sd->signerInfos) sd->signerInfos = sk_CMS_SignerInfo_new_null(); if (!sd->signerInfos || !sk_CMS_SignerInfo_push(sd->signerInfos, si)) goto merr; return si; merr: CMSerr(CMS_F_CMS_ADD1_SIGNER, ERR_R_MALLOC_FAILURE); err: M_ASN1_free_of(si, CMS_SignerInfo); return NULL; }
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) { EVP_MD_CTX *ctx = NULL; unsigned char *buf_in = NULL; int ret = -1, inl = 0; int mdnid, pknid; if (!pkey) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER); return -1; } if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); return -1; } ctx = EVP_MD_CTX_new(); if (ctx == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE); goto err; } /* Convert signature OID into digest and public key OIDs */ if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } if (mdnid == NID_undef) { if (!pkey->ameth || !pkey->ameth->item_verify) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } ret = pkey->ameth->item_verify(ctx, it, asn, a, signature, pkey); /* * Return value of 2 means carry on, anything else means we exit * straight away: either a fatal error of the underlying verification * routine handles all verification. */ if (ret != 2) goto err; ret = -1; } else { const EVP_MD *type; type = EVP_get_digestbynid(mdnid); if (type == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); goto err; } /* Check public key OID matches public key type */ if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_WRONG_PUBLIC_KEY_TYPE); goto err; } if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); ret = 0; goto err; } } inl = ASN1_item_i2d(asn, &buf_in, it); if (buf_in == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_MALLOC_FAILURE); goto err; } ret = EVP_DigestVerify(ctx, signature->data, (size_t)signature->length, buf_in, inl); if (ret <= 0) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_EVP_LIB); goto err; } ret = 1; err: OPENSSL_clear_free(buf_in, (unsigned int)inl); EVP_MD_CTX_free(ctx); return ret; }
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { const EVP_MD *evp_md; EVP_MD_CTX md; u_char digest[EVP_MAX_MD_SIZE], *sig = NULL; size_t slen; u_int dlen, len; int nid, ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) return SSH_ERR_INVALID_ARGUMENT; slen = RSA_size(key->rsa); if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; nid = (compat & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) return SSH_ERR_LIBCRYPTO_ERROR; if (EVP_DigestInit(&md, evp_md) != 1 || EVP_DigestUpdate(&md, data, datalen) != 1 || EVP_DigestFinal(&md, digest, &dlen) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((sig = malloc(slen)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (len < slen) { size_t diff = slen - len; memmove(sig + diff, sig, len); memset(sig, 0, diff); } else if (len > slen) { ret = SSH_ERR_INTERNAL_ERROR; goto out; } /* encode signature */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || (ret = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); if (lenp != NULL) *lenp = len; if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } ret = 0; out: bzero(digest, sizeof(digest)); bzero(&md, sizeof(md)); if (sig != NULL) { memset(sig, 's', slen); free(sig); } if (b != NULL) sshbuf_free(b); return 0; }
/* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i, j; BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body = NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher = NULL; EVP_CIPHER_CTX *evp_ctx = NULL; X509_ALGOR *enc_alg = NULL; STACK_OF(X509_ALGOR) *md_sk = NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; PKCS7_RECIP_INFO *ri = NULL; uint8_t *ek = NULL, *tkey = NULL; int eklen = 0, tkeylen = 0; if (p7 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); return NULL; } if (p7->d.ptr == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); return NULL; } i = OBJ_obj2nid(p7->type); p7->state = PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: /* * p7->d.sign->contents is a PKCS7 structure consisting of a contentType * field and optional content. * data_body is NULL if that structure has no (=detached) content * or if the contentType is wrong (i.e., not "data"). */ data_body = PKCS7_get_octet_string(p7->d.sign->contents); if (!PKCS7_is_detached(p7) && data_body == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_SIGNED_DATA_TYPE); goto err; } md_sk = p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk = p7->d.signed_and_enveloped->recipientinfo; md_sk = p7->d.signed_and_enveloped->md_algs; /* data_body is NULL if the optional EncryptedContent is missing. */ data_body = p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; case NID_pkcs7_enveloped: rsk = p7->d.enveloped->recipientinfo; enc_alg = p7->d.enveloped->enc_data->algorithm; /* data_body is NULL if the optional EncryptedContent is missing. */ data_body = p7->d.enveloped->enc_data->enc_data; evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* Detached content must be supplied via in_bio instead. */ if (data_body == NULL && in_bio == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) { xa = sk_X509_ALGOR_value(md_sk, i); if ((btmp = BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB); goto err; } j = OBJ_obj2nid(xa->algorithm); evp_md = EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp, evp_md); if (out == NULL) out = btmp; else BIO_push(out, btmp); btmp = NULL; } } if (evp_cipher != NULL) { if ((etmp = BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri = sk_PKCS7_RECIP_INFO_value(rsk, i); if (!pkcs7_cmp_ri(ri, pcert)) break; ri = NULL; } if (ri == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); goto err; } } /* If we haven't got a certificate try each ri in turn */ if (pcert == NULL) { /* Always attempt to decrypt all rinfo even * after sucess as a defence against MMA timing * attacks. */ for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri = sk_PKCS7_RECIP_INFO_value(rsk, i); if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0) goto err; ERR_clear_error(); } } else { /* Only exit on fatal errors, not decrypt failure */ if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0) goto err; ERR_clear_error(); } evp_ctx = NULL; BIO_get_cipher_ctx(etmp, &evp_ctx); if (EVP_CipherInit_ex(evp_ctx, evp_cipher, NULL, NULL, NULL, 0) <= 0) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0) goto err; /* Generate random key as MMA defence */ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); tkey = malloc(tkeylen); if (!tkey) goto err; if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) goto err; if (ek == NULL) { ek = tkey; eklen = tkeylen; tkey = NULL; } if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) { /* Use random key as MMA defence */ vigortls_zeroize(ek, eklen); free(ek); ek = tkey; eklen = tkeylen; tkey = NULL; } } /* Clear errors so we don't leak information useful in MMA */ ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0) goto err; if (ek) { vigortls_zeroize(ek, eklen); free(ek); ek = NULL; } if (tkey) { vigortls_zeroize(tkey, tkeylen); free(tkey); tkey = NULL; } if (out == NULL) out = etmp; else BIO_push(out, etmp); etmp = NULL; } if (in_bio != NULL) { bio = in_bio; } else { if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data, data_body->length); else { bio = BIO_new(BIO_s_mem()); if (bio == NULL) goto err; BIO_set_mem_eof_return(bio, 0); } if (bio == NULL) goto err; } BIO_push(out, bio); bio = NULL; if (0) { err: if (ek) { vigortls_zeroize(ek, eklen); free(ek); } if (tkey) { vigortls_zeroize(tkey, tkeylen); free(tkey); } if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out = NULL; } return (out); }
int int_rsa_verify(int dtype, const unsigned char *m, unsigned int m_len, unsigned char *rm, size_t *prm_len, const unsigned char *sigbuf, size_t siglen, RSA *rsa) { int i,ret=0,sigtype; unsigned char *s; X509_SIG *sig=NULL; #ifdef OPENSSL_FIPS if (FIPS_mode() && !(rsa->meth->flags & RSA_FLAG_FIPS_METHOD) && !(rsa->flags & RSA_FLAG_NON_FIPS_ALLOW)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_NON_FIPS_RSA_METHOD); return 0; } #endif if (siglen != (unsigned int)RSA_size(rsa)) { RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_WRONG_SIGNATURE_LENGTH); return(0); } if((dtype == NID_md5_sha1) && rm) { i = RSA_public_decrypt((int)siglen, sigbuf,rm,rsa,RSA_PKCS1_PADDING); if (i <= 0) return 0; *prm_len = i; return 1; } s=(unsigned char *)OPENSSL_malloc((unsigned int)siglen); if (s == NULL) { RSAerr(RSA_F_INT_RSA_VERIFY,ERR_R_MALLOC_FAILURE); goto err; } if((dtype == NID_md5_sha1) && (m_len != SSL_SIG_LENGTH) ) { RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_INVALID_MESSAGE_LENGTH); goto err; } i=RSA_public_decrypt((int)siglen,sigbuf,s,rsa,RSA_PKCS1_PADDING); if (i <= 0) goto err; /* Oddball MDC2 case: signature can be OCTET STRING. * check for correct tag and length octets. */ if (dtype == NID_mdc2 && i == 18 && s[0] == 0x04 && s[1] == 0x10) { if (rm) { memcpy(rm, s + 2, 16); *prm_len = 16; ret = 1; } else if(memcmp(m, s + 2, 16)) RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE); else ret = 1; } /* Special case: SSL signature */ if(dtype == NID_md5_sha1) { if((i != SSL_SIG_LENGTH) || memcmp(s, m, SSL_SIG_LENGTH)) RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE); else ret = 1; } else { const unsigned char *p=s; sig=d2i_X509_SIG(NULL,&p,(long)i); if (sig == NULL) goto err; /* Excess data can be used to create forgeries */ if(p != s+i || !rsa_check_digestinfo(sig, s, i)) { RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE); goto err; } /* Parameters to the signature algorithm can also be used to create forgeries */ if(sig->algor->parameter && ASN1_TYPE_get(sig->algor->parameter) != V_ASN1_NULL) { RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE); goto err; } sigtype=OBJ_obj2nid(sig->algor->algorithm); #ifdef RSA_DEBUG /* put a backward compatibility flag in EAY */ fprintf(stderr,"in(%s) expect(%s)\n",OBJ_nid2ln(sigtype), OBJ_nid2ln(dtype)); #endif if (sigtype != dtype) { if (((dtype == NID_md5) && (sigtype == NID_md5WithRSAEncryption)) || ((dtype == NID_md2) && (sigtype == NID_md2WithRSAEncryption))) { /* ok, we will let it through */ #if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16) fprintf(stderr,"signature has problems, re-make with post SSLeay045\n"); #endif } else { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_ALGORITHM_MISMATCH); goto err; } } if (rm) { const EVP_MD *md; md = EVP_get_digestbynid(dtype); if (md && (EVP_MD_size(md) != sig->digest->length)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH); else { memcpy(rm, sig->digest->data, sig->digest->length); *prm_len = sig->digest->length; ret = 1; } } else if (((unsigned int)sig->digest->length != m_len) || (memcmp(m,sig->digest->data,m_len) != 0)) { RSAerr(RSA_F_INT_RSA_VERIFY,RSA_R_BAD_SIGNATURE); } else ret=1; } err: if (sig != NULL) X509_SIG_free(sig); if (s != NULL) { OPENSSL_cleanse(s,(unsigned int)siglen); OPENSSL_free(s); } return(ret); }
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp, *mdc; int ret = 0, i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; EVP_MD_CTX_init(&mdc_tmp); if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type = OBJ_obj2nid(si->digest_alg->algorithm); btmp = bio; for (;;) { if ((btmp == NULL) || ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp, &mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; /* Workaround for some broken clients that put the signature * OID instead of the digest OID in digest_alg->algorithm */ if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) break; btmp = BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ if (!EVP_MD_CTX_copy_ex(&mdc_tmp, mdc)) goto err; sk = si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { uint8_t md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; unsigned int md_len; int alen; ASN1_OCTET_STRING *message_digest; if (!EVP_DigestFinal_ex(&mdc_tmp, md_dat, &md_len)) goto err; message_digest = PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data, md_dat, md_len))) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE); ret = -1; goto err; } if (!EVP_VerifyInit_ex(&mdc_tmp, EVP_get_digestbynid(md_type), NULL)) goto err; alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); if (alen <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB); ret = -1; goto err; } if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen)) goto err; free(abuf); } os = si->enc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } i = EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret = -1; goto err; } else ret = 1; err: EVP_MD_CTX_cleanup(&mdc_tmp); return (ret); }
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509) { ASN1_OCTET_STRING *os; EVP_MD_CTX mdc_tmp,*mdc; unsigned char *pp,*p; int ret=0,i; int md_type; STACK_OF(X509_ATTRIBUTE) *sk; BIO *btmp; EVP_PKEY *pkey; if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); goto err; } md_type=OBJ_obj2nid(si->digest_alg->algorithm); btmp=bio; for (;;) { if ((btmp == NULL) || ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } BIO_get_md_ctx(btmp,&mdc); if (mdc == NULL) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_INTERNAL_ERROR); goto err; } if (EVP_MD_CTX_type(mdc) == md_type) break; btmp=BIO_next(btmp); } /* mdc is the digest ctx that we want, unless there are attributes, * in which case the digest is the signed attributes */ memcpy(&mdc_tmp,mdc,sizeof(mdc_tmp)); sk=si->auth_attr; if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) { unsigned char md_dat[EVP_MAX_MD_SIZE]; unsigned int md_len; ASN1_OCTET_STRING *message_digest; EVP_DigestFinal(&mdc_tmp,md_dat,&md_len); message_digest=PKCS7_digest_from_attributes(sk); if (!message_digest) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); goto err; } if ((message_digest->length != (int)md_len) || (memcmp(message_digest->data,md_dat,md_len))) { #if 0 { int ii; for (ii=0; ii<message_digest->length; ii++) printf("%02X",message_digest->data[ii]); printf(" sent\n"); for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n"); } #endif PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE); ret= -1; goto err; } EVP_VerifyInit(&mdc_tmp,EVP_get_digestbynid(md_type)); /* Note: when forming the encoding of the attributes we * shouldn't reorder them or this will break the signature. * This is done by using the IS_SEQUENCE flag. */ i=i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,NULL,i2d_X509_ATTRIBUTE, V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); pp=OPENSSL_malloc(i); p=pp; i2d_ASN1_SET_OF_X509_ATTRIBUTE(sk,&p,i2d_X509_ATTRIBUTE, V_ASN1_SET,V_ASN1_UNIVERSAL, IS_SEQUENCE); EVP_VerifyUpdate(&mdc_tmp,pp,i); OPENSSL_free(pp); } os=si->enc_digest; pkey = X509_get_pubkey(x509); if (!pkey) { ret = -1; goto err; } #ifndef NO_DSA if(pkey->type == EVP_PKEY_DSA) mdc_tmp.digest=EVP_dss1(); #endif i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); EVP_PKEY_free(pkey); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE); ret= -1; goto err; } else ret=1; err: return(ret); }
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) { EVP_MD_CTX ctx; const EVP_MD *type = NULL; unsigned char *buf_in=NULL; int ret= -1,inl; int mdnid, pknid; if (!pkey) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER); return -1; } if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); return -1; } EVP_MD_CTX_init(&ctx); /* Convert signature OID into digest and public key OIDs */ if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } type=EVP_get_digestbynid(mdnid); if (type == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); goto err; } /* Check public key OID matches public key type */ if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE); goto err; } if (!EVP_VerifyInit_ex(&ctx,type, NULL)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); ret=0; goto err; } inl = ASN1_item_i2d(asn, &buf_in, it); if (buf_in == NULL) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_MALLOC_FAILURE); goto err; } EVP_VerifyUpdate(&ctx,(unsigned char *)buf_in,inl); OPENSSL_cleanse(buf_in,(unsigned int)inl); OPENSSL_free(buf_in); if (EVP_VerifyFinal(&ctx,(unsigned char *)signature->data, (unsigned int)signature->length,pkey) <= 0) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); ret=0; goto err; } /* we don't need to zero the 'ctx' because we just checked * public information */ /* memset(&ctx,0,sizeof(ctx)); */ ret=1; err: EVP_MD_CTX_cleanup(&ctx); return(ret); }
int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md, int en_de) { unsigned char *salt, key[EVP_MAX_KEY_LENGTH]; int saltlen, iter; int rv = 0; unsigned int keylen = 0; int prf_nid, hmac_md_nid; PBKDF2PARAM *kdf = NULL; const EVP_MD *prfmd; if (EVP_CIPHER_CTX_cipher(ctx) == NULL) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_NO_CIPHER_SET); goto err; } keylen = EVP_CIPHER_CTX_key_length(ctx); OPENSSL_assert(keylen <= sizeof(key)); /* Decode parameter */ kdf = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBKDF2PARAM), param); if (kdf == NULL) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_DECODE_ERROR); goto err; } keylen = EVP_CIPHER_CTX_key_length(ctx); /* Now check the parameters of the kdf */ if (kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_KEYLENGTH); goto err; } if (kdf->prf) prf_nid = OBJ_obj2nid(kdf->prf->algorithm); else prf_nid = NID_hmacWithSHA1; if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0)) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); goto err; } prfmd = EVP_get_digestbynid(hmac_md_nid); if (prfmd == NULL) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF); goto err; } if (kdf->salt->type != V_ASN1_OCTET_STRING) { EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_SALT_TYPE); goto err; } /* it seems that its all OK */ salt = kdf->salt->value.octet_string->data; saltlen = kdf->salt->value.octet_string->length; iter = ASN1_INTEGER_get(kdf->iter); if (!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd, keylen, key)) goto err; rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de); err: OPENSSL_cleanse(key, keylen); PBKDF2PARAM_free(kdf); return rv; }
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { const EVP_MD *evp_md; EVP_MD_CTX md; u_char *sig = NULL; u_int slen = 0, len; #ifdef USE_LEGACY_RSA_SIGN u_char digest[EVP_MAX_MD_SIZE]; u_int dlen; #endif int ok, nid; Buffer b; if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { error("ssh_rsa_sign: no RSA key"); return -1; } nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); return -1; } #ifdef USE_LEGACY_RSA_SIGN EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md, data, datalen); EVP_DigestFinal(&md, digest, &dlen); slen = RSA_size(key->rsa); sig = xmalloc(slen); ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); memset(digest, 'd', sizeof(digest)); #else /*ndef USE_LEGACY_RSA_SIGN*/ { EVP_PKEY *pkey = NULL; ok = -1; pkey = EVP_PKEY_new(); if (pkey == NULL) { error("%s: out of memory", __func__); goto done; } EVP_PKEY_set1_RSA(pkey, key->rsa); slen = EVP_PKEY_size(pkey); sig = xmalloc(slen); /*fatal on error*/ ssh_EVP_MD_CTX_init(&md); ok = ssh_EVP_SignInit_ex(&md, evp_md, NULL); if (ok <= 0) { char ebuf[256]; error("%s: EVP_SignInit_ex fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } ok = ssh_EVP_SignUpdate(&md, data, datalen); if (ok <= 0) { char ebuf[256]; error("%s: EVP_SignUpdate fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } ok = EVP_SignFinal(&md, sig, &len, pkey); if (ok <= 0) { char ebuf[256]; error("%s: SignFinal fail with errormsg='%.*s'" , __func__ , (int)sizeof(ebuf), openssl_errormsg(ebuf, sizeof(ebuf))); goto clean; } clean: ssh_EVP_MD_CTX_cleanup(&md); done: if (pkey != NULL) EVP_PKEY_free(pkey); } #endif /*ndef USE_LEGACY_RSA_SIGN*/ if (ok <= 0) { #ifdef USE_LEGACY_RSA_SIGN int ecode = ERR_get_error(); error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL)); #endif /*def USE_LEGACY_RSA_SIGN*/ xfree(sig); return -1; } if (len < slen) { u_int diff = slen - len; debug("slen %u > len %u", slen, len); memmove(sig + diff, sig, len); memset(sig, 0, diff); } else if (len > slen) { error("ssh_rsa_sign: slen %u slen2 %u", slen, len); xfree(sig); return -1; } /* encode signature */ buffer_init(&b); buffer_put_cstring(&b, "ssh-rsa"); buffer_put_string(&b, sig, slen); len = buffer_len(&b); if (lenp != NULL) *lenp = len; if (sigp != NULL) { *sigp = xmalloc(len); memcpy(*sigp, buffer_ptr(&b), len); } buffer_free(&b); memset(sig, 's', slen); xfree(sig); return 0; }
/* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i,j; BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; unsigned char *tmp=NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body=NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher=NULL; EVP_CIPHER_CTX *evp_ctx=NULL; X509_ALGOR *enc_alg=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; X509_ALGOR *xalg=NULL; PKCS7_RECIP_INFO *ri=NULL; i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: data_body=PKCS7_get_octet_string(p7->d.sign->contents); md_sk=p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; data_body=p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } xalg=p7->d.signed_and_enveloped->enc_data->algorithm; break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; enc_alg=p7->d.enveloped->enc_data->algorithm; data_body=p7->d.enveloped->enc_data->enc_data; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } xalg=p7->d.enveloped->enc_data->algorithm; break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) { xa=sk_X509_ALGOR_value(md_sk,i); if ((btmp=BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } j=OBJ_obj2nid(xa->algorithm); evp_md=EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,evp_md); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } } if (evp_cipher != NULL) { #if 0 unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char *p; int keylen,ivlen; int max; X509_OBJECT ret; #endif int jj; if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri=sk_PKCS7_RECIP_INFO_value(rsk,i); if (!pkcs7_cmp_ri(ri, pcert)) break; ri=NULL; } if (ri == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); goto err; } } jj=EVP_PKEY_size(pkey); tmp=(unsigned char *)OPENSSL_malloc(jj+10); if (tmp == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_MALLOC_FAILURE); goto err; } /* If we haven't got a certificate try each ri in turn */ if (pcert == NULL) { for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri=sk_PKCS7_RECIP_INFO_value(rsk,i); jj=EVP_PKEY_decrypt(tmp, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); if (jj > 0) break; ERR_clear_error(); ri = NULL; } if (ri == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY); goto err; } } else { jj=EVP_PKEY_decrypt(tmp, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); if (jj <= 0) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB); goto err; } } evp_ctx=NULL; BIO_get_cipher_ctx(etmp,&evp_ctx); if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) goto err; if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj)) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH); goto err; } } if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0) goto err; OPENSSL_cleanse(tmp,jj); if (out == NULL) out=etmp; else BIO_push(out,etmp); etmp=NULL; } #if 1 if (PKCS7_is_detached(p7) || (in_bio != NULL)) { bio=in_bio; } else { #if 0 bio=BIO_new(BIO_s_mem()); /* We need to set this so that when we have read all * the data, the encrypt BIO, if present, will read * EOF and encode the last few bytes */ BIO_set_mem_eof_return(bio,0); if (data_body->length > 0) BIO_write(bio,(char *)data_body->data,data_body->length); #else if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data,data_body->length); else { bio=BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bio,0); } #endif } BIO_push(out,bio); bio=NULL; #endif if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out=NULL; } if (tmp != NULL) OPENSSL_free(tmp); return(out); }
int int_rsa_verify(int dtype, const unsigned char *m, unsigned int m_len, unsigned char *rm, size_t *prm_len, const unsigned char *sigbuf, size_t siglen, RSA *rsa) { int i, ret = 0, sigtype; unsigned char *s; X509_SIG *sig = NULL; if (siglen != (unsigned int)RSA_size(rsa)) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_WRONG_SIGNATURE_LENGTH); return 0; } if ((dtype == NID_md5_sha1) && rm) { i = RSA_public_decrypt((int)siglen, sigbuf, rm, rsa, RSA_PKCS1_PADDING); if (i <= 0) return 0; *prm_len = i; return 1; } s = malloc((unsigned int)siglen); if (s == NULL) { RSAerr(RSA_F_INT_RSA_VERIFY, ERR_R_MALLOC_FAILURE); goto err; } if (dtype == NID_md5_sha1 && m_len != SSL_SIG_LENGTH) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_MESSAGE_LENGTH); goto err; } i = RSA_public_decrypt((int)siglen, sigbuf, s, rsa, RSA_PKCS1_PADDING); if (i <= 0) goto err; /* * Oddball MDC2 case: signature can be OCTET STRING. * check for correct tag and length octets. */ if (dtype == NID_mdc2 && i == 18 && s[0] == 0x04 && s[1] == 0x10) { if (rm) { memcpy(rm, s + 2, 16); *prm_len = 16; ret = 1; } else if (memcmp(m, s + 2, 16)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); else ret = 1; } /* Special case: SSL signature */ if (dtype == NID_md5_sha1) { if (i != SSL_SIG_LENGTH || memcmp(s, m, SSL_SIG_LENGTH)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); else ret = 1; } else { const unsigned char *p = s; sig = d2i_X509_SIG(NULL, &p, (long)i); if (sig == NULL) goto err; /* Excess data can be used to create forgeries */ if (p != s + i) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); goto err; } /* Parameters to the signature algorithm can also be used to create forgeries */ if (sig->algor->parameter && ASN1_TYPE_get(sig->algor->parameter) != V_ASN1_NULL) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); goto err; } sigtype = OBJ_obj2nid(sig->algor->algorithm); if (sigtype != dtype) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_ALGORITHM_MISMATCH); goto err; } if (rm) { const EVP_MD *md; md = EVP_get_digestbynid(dtype); if (md && (EVP_MD_size(md) != sig->digest->length)) RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH); else { memcpy(rm, sig->digest->data, sig->digest->length); *prm_len = sig->digest->length; ret = 1; } } else if ((unsigned int)sig->digest->length != m_len || memcmp(m, sig->digest->data, m_len) != 0) { RSAerr(RSA_F_INT_RSA_VERIFY, RSA_R_BAD_SIGNATURE); } else ret = 1; } err: if (sig != NULL) X509_SIG_free(sig); if (s != NULL) { OPENSSL_cleanse(s, (unsigned int)siglen); free(s); } return ret; }
/* int */ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) { int i,j; BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; unsigned char *tmp=NULL; X509_ALGOR *xa; ASN1_OCTET_STRING *data_body=NULL; const EVP_MD *evp_md; const EVP_CIPHER *evp_cipher=NULL; EVP_CIPHER_CTX *evp_ctx=NULL; X509_ALGOR *enc_alg=NULL; STACK_OF(X509_ALGOR) *md_sk=NULL; STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; PKCS7_RECIP_INFO *ri=NULL; if (p7 == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER); return NULL; } if (p7->d.ptr == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); return NULL; } i=OBJ_obj2nid(p7->type); p7->state=PKCS7_S_HEADER; switch (i) { case NID_pkcs7_signed: /* * p7->d.sign->contents is a PKCS7 structure consisting of a contentType * field and optional content. * data_body is NULL if that structure has no (=detached) content * or if the contentType is wrong (i.e., not "data"). */ data_body=PKCS7_get_octet_string(p7->d.sign->contents); md_sk=p7->d.sign->md_algs; break; case NID_pkcs7_signedAndEnveloped: rsk=p7->d.signed_and_enveloped->recipientinfo; md_sk=p7->d.signed_and_enveloped->md_algs; /* data_body is NULL if the optional EncryptedContent is missing. */ data_body=p7->d.signed_and_enveloped->enc_data->enc_data; enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; case NID_pkcs7_enveloped: rsk=p7->d.enveloped->recipientinfo; enc_alg=p7->d.enveloped->enc_data->algorithm; /* data_body is NULL if the optional EncryptedContent is missing. */ data_body=p7->d.enveloped->enc_data->enc_data; evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); if (evp_cipher == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); goto err; } break; default: PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); goto err; } /* Detached content must be supplied via in_bio instead. */ if (data_body == NULL && in_bio == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); goto err; } /* We will be checking the signature */ if (md_sk != NULL) { for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) { xa=sk_X509_ALGOR_value(md_sk,i); if ((btmp=BIO_new(BIO_f_md())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } j=OBJ_obj2nid(xa->algorithm); evp_md=EVP_get_digestbynid(j); if (evp_md == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); goto err; } BIO_set_md(btmp,evp_md); if (out == NULL) out=btmp; else BIO_push(out,btmp); btmp=NULL; } } if (evp_cipher != NULL) { #if 0 unsigned char key[EVP_MAX_KEY_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char *p; int keylen,ivlen; int max; X509_OBJECT ret; #endif unsigned char *tkey = NULL; int tkeylen; int jj; if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); goto err; } /* It was encrypted, we need to decrypt the secret key * with the private key */ /* Find the recipientInfo which matches the passed certificate * (if any) */ if (pcert) { for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri=sk_PKCS7_RECIP_INFO_value(rsk,i); if (!pkcs7_cmp_ri(ri, pcert)) break; ri=NULL; } if (ri == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); goto err; } } jj=EVP_PKEY_size(pkey); tmp=(unsigned char *)OPENSSL_malloc(jj+10); if (tmp == NULL) { PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_MALLOC_FAILURE); goto err; } /* If we haven't got a certificate try each ri in turn */ if (pcert == NULL) { /* Temporary storage in case EVP_PKEY_decrypt * overwrites output buffer on error. */ unsigned char *tmp2; tmp2 = OPENSSL_malloc(jj); if (!tmp2) goto err; jj = -1; /* Always attempt to decrypt all cases to avoid * leaking timing information about a successful * decrypt. */ for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { int tret; ri=sk_PKCS7_RECIP_INFO_value(rsk,i); tret=EVP_PKEY_decrypt(tmp2, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); if (tret > 0) { memcpy(tmp, tmp2, tret); OPENSSL_cleanse(tmp2, tret); jj = tret; } ERR_clear_error(); } OPENSSL_free(tmp2); } else { jj=EVP_PKEY_decrypt(tmp, M_ASN1_STRING_data(ri->enc_key), M_ASN1_STRING_length(ri->enc_key), pkey); ERR_clear_error(); } evp_ctx=NULL; BIO_get_cipher_ctx(etmp,&evp_ctx); if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) goto err; /* Generate random key to counter MMA */ tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); tkey = OPENSSL_malloc(tkeylen); if (!tkey) goto err; if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) goto err; /* If we have no key use random key */ if (jj <= 0) { OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } if (jj != tkeylen) { /* Some S/MIME clients don't use the same key * and effective key length. The key length is * determined by the size of the decrypted RSA key. */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj)) { /* As MMA defence use random key instead */ OPENSSL_cleanse(tmp, jj); OPENSSL_free(tmp); jj = tkeylen; tmp = tkey; tkey = NULL; } } ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0) goto err; OPENSSL_cleanse(tmp,jj); if (tkey) { OPENSSL_cleanse(tkey, tkeylen); OPENSSL_free(tkey); } if (out == NULL) out=etmp; else BIO_push(out,etmp); etmp=NULL; } #if 1 if (in_bio != NULL) { bio=in_bio; } else { #if 0 bio=BIO_new(BIO_s_mem()); /* We need to set this so that when we have read all * the data, the encrypt BIO, if present, will read * EOF and encode the last few bytes */ BIO_set_mem_eof_return(bio,0); if (data_body->length > 0) BIO_write(bio,(char *)data_body->data,data_body->length); #else if (data_body->length > 0) bio = BIO_new_mem_buf(data_body->data,data_body->length); else { bio=BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bio,0); } if (bio == NULL) goto err; #endif } BIO_push(out,bio); bio=NULL; #endif if (0) { err: if (out != NULL) BIO_free_all(out); if (btmp != NULL) BIO_free_all(btmp); if (etmp != NULL) BIO_free_all(etmp); if (bio != NULL) BIO_free_all(bio); out=NULL; } if (tmp != NULL) OPENSSL_free(tmp); return(out); }