ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Bytes) */ unsigned bytes; unsigned char* data; ERL_NIF_TERM ret; if (!enif_get_uint(env, argv[0], &bytes)) { return enif_make_badarg(env); } data = enif_make_new_binary(env, bytes, &ret); if ( RAND_bytes(data, bytes) != 1) { return atom_false; } ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); return ret; }
static ERL_NIF_TERM tree_pair_dsha256_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin1, bin2; if (!enif_inspect_binary(env, argv[0], &bin1) || bin1.size != 32 || !enif_inspect_binary(env, argv[1], &bin2) || bin2.size != 32) return enif_make_badarg(env); ERL_NIF_TERM ret; unsigned char in[64]; unsigned char *final_hash = enif_make_new_binary(env, 32, &ret); reverse32(&in[0], bin1.data); reverse32(&in[32], bin2.data); double_sha256(in, 64, final_hash); reverse32(final_hash, final_hash); return ret; }
static ERL_NIF_TERM mem_to_binary(ErlNifEnv *env, const unsigned char *cstr, size_t len) { unsigned char *bin; ERL_NIF_TERM term; if(cstr) { bin = enif_make_new_binary(env, len, &term); memcpy(bin, cstr, len); return term; } else { return enif_make_atom(env, "null"); } }
static ERL_NIF_TERM escape_cdata(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; ERL_NIF_TERM output; struct buf *rbuf; int i; if (argc != 1) { return enif_make_badarg(env); } // CData should be iolist() or binary() if (enif_is_binary(env, argv[0])) { if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } else { if (!enif_inspect_iolist_as_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } rbuf = init_buf(env, EXML_CDATA_BUF_SIZE); for (i = 0; i < input.size; i++) { switch (input.data[i]) { case '&': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, "&", 5); break; case '<': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, "<", 4); break; case '>': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, ">", 4); break; default: buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, input.data[i]); break; }; }; unsigned char* data = enif_make_new_binary(env, rbuf->len, &output); memcpy(data, rbuf->b, rbuf->len); destroy_buf(env, rbuf); return output; }
static ERL_NIF_TERM sum_r(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin; ErlNifSInt64 chunk; // size to be compressed ERL_NIF_TERM r; ErlNifSInt64* vs; ErlNifSInt64* target; ErlNifSInt64 aggr; // Aggregator uint32_t target_i = 0; // target position uint32_t count; uint32_t pos = 0; uint32_t target_size; if (argc != 2) return enif_make_badarg(env); GET_CHUNK(chunk); GET_BIN(0, bin, count, vs); target_size = ceil((double) count / chunk) * sizeof(ErlNifSInt64); if (! (target = (ErlNifSInt64*) enif_make_new_binary(env, target_size, &r))) return enif_make_badarg(env); // TODO return propper error if (count > 0) { aggr = vs[0]; pos = 2; for (uint32_t i = 1; i < count; i++, pos++) { if (pos == count) { target[target_i] = aggr; target_i++; aggr = vs[i]; pos = 0; } else { aggr += vs[i]; } } if (count % chunk) { target[target_i] = aggr + vs[count - 1] * (chunk - (count % chunk)); } else { target[target_i] = aggr; } } return r; }
static ERL_NIF_TERM empty(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin; ERL_NIF_TERM r; ErlNifSInt64* vs; ErlNifSInt64* target; ErlNifSInt64 chunk; // size to be compressed ErlNifSInt64 target_i = 0; // target position ErlNifSInt64 pos = 0; // position in chunk ErlNifSInt64 aggr = 0; // aggregated value for this chunk int count; int target_size; if (argc != 2) return enif_make_badarg(env); GET_CHUNK(chunk); GET_BIN(0, bin, count, vs); target_size = ceil((double) count / chunk) * sizeof(ErlNifSInt64); if (! (target = (ErlNifSInt64*) enif_make_new_binary(env, target_size, &r))) return enif_make_badarg(env); // TODO return propper error if (count == 0) return r; pos = 0; for (int i = 0; i < count; i++, pos++) { if (pos == chunk) { target[target_i] = TO_DDB(aggr); target_i++; aggr = !IS_SET(vs[i]); pos = 0; } else { aggr += !IS_SET(vs[i]); } } if (count % chunk) { aggr += (chunk - (count % chunk)); } target[target_i] = TO_DDB(aggr); return r; }
static ERL_NIF_TERM hex(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { md5ctx* ctx; ERL_NIF_TERM ret; unsigned char* hash = enif_make_new_binary(env, 16, &ret); if(argc != 1) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], md5_type, (void**) &ctx)) return enif_make_badarg(env); if(!MD5_Final(hash, &(ctx->md5))) return make_atom(env, "finalization_error"); ctx->finalized = 1; return ret; }
static ERL_NIF_TERM gdal_nif_tile_to_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { gdal_tile_handle* ti; if (!enif_get_resource(env, argv[0], gdal_tile_RESOURCE, (void**)&ti)) { return enif_make_badarg(env); } ErlNifBinary tilefilenameBin; if (!enif_inspect_iolist_as_binary(env, argv[1], &tilefilenameBin) || (tilefilenameBin.size >= FILENAME_LEN)) { return make_error_msg(env, "filename error, maybe too long"); } char rasterFormatCode[16] = ""; if (enif_get_string(env, argv[2], rasterFormatCode, 16, ERL_NIF_LATIN1) <= 0) { return enif_make_badarg(env); } char tilefilename[FILENAME_LEN] = ""; memcpy(tilefilename, tilefilenameBin.data, tilefilenameBin.size); DEBUG("passed tilefilename: %s\r\n", tilefilename); GDALDriverH hOutDriver = GDALGetDriverByName(rasterFormatCode); if ( ! ti->options_resampling || (strcmp("antialias", ti->options_resampling) != 0) ) { char vsimemFileName[128] = ""; sprintf(vsimemFileName, "/vsimem/%s", tilefilename); GDALDatasetH tileBinDataset = GDALCreateCopy(hOutDriver, vsimemFileName, ti->dstile, FALSE, NULL, NULL, NULL); vsi_l_offset binDataLength; int bUnlinkAndSeize = FALSE; GByte* binData = VSIGetMemFileBuffer(vsimemFileName, &binDataLength, bUnlinkAndSeize); DEBUG("vsimem: %s, bin len: %d\r\n", vsimemFileName, binDataLength); ERL_NIF_TERM binTerm; unsigned char* buf = enif_make_new_binary(env, binDataLength, &binTerm); memcpy(buf, binData, binDataLength); // CPLFree(binData); GDALClose(tileBinDataset); return enif_make_tuple2(env, ATOM_OK, binTerm); } return make_error_msg(env, "wrong resampling"); }
ERL_NIF_TERM ucrypto_ripemd160_update_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { RIPEMD160_CTX *new_context; ErlNifBinary context_binary, data_binary; ERL_NIF_TERM result; if (! enif_inspect_binary(env, argv[0], &context_binary) || context_binary.size != sizeof(RIPEMD160_CTX)) return enif_make_badarg(env); if (! enif_inspect_iolist_as_binary(env, argv[1], &data_binary)) return enif_make_badarg(env); new_context = (RIPEMD160_CTX *)enif_make_new_binary(env, sizeof(RIPEMD160_CTX), &result); memcpy(new_context, context_binary.data, sizeof(RIPEMD160_CTX)); RIPEMD160_Update(new_context, data_binary.data, data_binary.size); return result; }
ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn) { int bn_len; unsigned char *bin_ptr; ERL_NIF_TERM term; /* Copy the bignum into an erlang binary. */ if ((bn_len = BN_num_bytes(bn)) < 0) goto err; if ((bin_ptr = enif_make_new_binary(env, (size_t)bn_len, &term)) == NULL) goto err; if (BN_bn2bin(bn, bin_ptr) < 0) goto err; return term; err: return atom_error; }
static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM ret; if (resource_dtor_last != NULL) { ERL_NIF_TERM bin; memcpy(enif_make_new_binary(env, resource_dtor_last_sz, &bin), resource_dtor_last_data, resource_dtor_last_sz); ret = enif_make_tuple3(env, enif_make_long(env, (long)resource_dtor_last), bin, enif_make_int(env, resource_dtor_cnt)); } else { ret = enif_make_list(env,0); } resource_dtor_last = NULL; resource_dtor_last_sz = 0; resource_dtor_cnt = 0; return ret; }
static ERL_NIF_TERM transpose(ErlNifEnv *env, int32_t argc, const ERL_NIF_TERM *argv) { ErlNifBinary matrix; ERL_NIF_TERM result; float *matrix_data, *result_data; int32_t data_size; size_t result_size; (void)(argc); if (!enif_inspect_binary(env, argv[0], &matrix)) return enif_make_badarg(env); matrix_data = (float *) matrix.data; data_size = (int32_t) (matrix_data[0] * matrix_data[1] + 2); result_size = sizeof(float) * data_size; result_data = (float *) enif_make_new_binary(env, result_size, &result); matrix_transpose(matrix_data, result_data); return result; }
ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn) { int dlen; unsigned char* ptr; ERL_NIF_TERM ret; if (bn == NULL) return atom_undefined; dlen = BN_num_bytes(bn); if (dlen < 0) goto err; if ((ptr = enif_make_new_binary(env, (size_t)dlen, &ret)) == NULL) goto err; BN_bn2bin(bn, ptr); ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen); return ret; err: return enif_make_badarg(env); }
posix_errno_t efile_list_dir(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result) { ERL_NIF_TERM list_head; struct dirent *dir_entry; DIR *dir_stream; dir_stream = opendir((const char*)path->data); if(dir_stream == NULL) { posix_errno_t saved_errno = errno; *result = enif_make_list(env, 0); return saved_errno; } list_head = enif_make_list(env, 0); dir_entry = readdir(dir_stream); while(dir_entry != NULL) { int name_length = strlen(dir_entry->d_name); if(!is_ignored_name(name_length, dir_entry->d_name)) { unsigned char *name_bytes; ERL_NIF_TERM name_term; name_bytes = enif_make_new_binary(env, name_length, &name_term); sys_memcpy(name_bytes, dir_entry->d_name, name_length); list_head = enif_make_list_cell(env, name_term, list_head); } dir_entry = readdir(dir_stream); } (*result) = list_head; closedir(dir_stream); return 0; }
static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp) { ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */ while (*headp != NULL) { CallInfo* call = *headp; ERL_NIF_TERM func_term = enif_make_atom(env,call->func_name); ERL_NIF_TERM tpl; if (call->arg != NULL) { ERL_NIF_TERM arg_bin; memcpy(enif_make_new_binary(env, call->arg_sz, &arg_bin), call->arg, call->arg_sz); func_term = enif_make_tuple2(env, func_term, arg_bin); } tpl = enif_make_tuple4(env, func_term, enif_make_int(env,call->lib_ver), enif_make_int(env,call->static_cntA), enif_make_int(env,call->static_cntB)); list = enif_make_list_cell(env, tpl, list); *headp = call->next; enif_free(call); } return list; }
static ERL_NIF_TERM dot(ErlNifEnv *env, int32_t argc, const ERL_NIF_TERM *argv) { ErlNifBinary first, second; ERL_NIF_TERM result; float *first_data, *second_data, *result_data; int32_t data_size; size_t result_size; (void)(argc); if (!enif_inspect_binary(env, argv[0], &first )) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &second)) return enif_make_badarg(env); first_data = (float *) first.data; second_data = (float *) second.data; data_size = (int32_t) (first_data[0] * second_data[1] + 2); result_size = sizeof(float) * data_size; result_data = (float *) enif_make_new_binary(env, result_size, &result); matrix_dot(first_data, second_data, result_data); return result; }
static ERL_NIF_TERM avg(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary bin; ERL_NIF_TERM r; ErlNifSInt64* vs; ErlNifSInt64* target; ErlNifSInt64 chunk; // size to be compressed ErlNifSInt64 target_i = 0; // target position ErlNifSInt64 pos = 0; // position in chunk ErlNifSInt64 aggr = 0; // aggregated value for this chunk ErlNifSInt64 last = 0; int count; int has_value = 0; int has_last = 0; int target_size; if (argc != 2) return enif_make_badarg(env); GET_CHUNK(chunk); GET_BIN(0, bin, count, vs); target_size = ceil((double) count / chunk) * sizeof(ErlNifSInt64); if (! (target = (ErlNifSInt64*) enif_make_new_binary(env, target_size, &r))) return enif_make_badarg(env); // TODO return propper error // If we don't have any input data we can return right away. if (count == 0) return r; // We know we have at least one element in the list so our // aggregator will start with this if (IS_SET(vs[0])) { aggr = FROM_DDB(vs[0]); last = aggr; has_value = 1; has_last = 1; }; pos = 1; // We itterate over the remining i .. count-1 elements for (int i = 1; i < count; i++, pos++) { if (pos == chunk) { if (has_value) { target[target_i] = TO_DDB(aggr / chunk); } else { target[target_i] = 0; } target_i++; has_value = IS_SET(vs[i]); if (has_value) { aggr = FROM_DDB(vs[i]); last = aggr; has_last = 1; } else if (has_last) { aggr = last; has_value = 1; } pos = 0; } else if (!has_value) { if (IS_SET(vs[i])) { aggr = FROM_DDB(vs[i]); last = aggr; has_value = 1; has_last = 1; }; } else { if (IS_SET(vs[i])) { last = FROM_DDB(vs[i]); aggr += last; has_last = 1; has_value = 1; } else if (has_last) { aggr += last; has_value = 1; } } } if (has_value) { if (count % chunk) { aggr += (last * (chunk - (count % chunk))); } target[target_i] = TO_DDB(aggr / chunk); } else { target[target_i] = 0; } return r; }
int dec_string(Decoder* d, ERL_NIF_TERM* value) { int has_escape = 0; int num_escapes = 0; int st; int ulen; int ui; int hi; int lo; char* chrbuf; int chrpos; if(d->p[d->i] != '\"') { return 0; } d->i++; st = d->i; while(d->i < d->len) { if(d->u[d->i] < 0x20) { return 0; } else if(d->p[d->i] == '\"') { d->i++; goto parse; } else if(d->p[d->i] == '\\') { if(d->i+1 >= d->len) { return 0; } has_escape = 1; num_escapes += 1; d->i++; switch(d->p[d->i]) { case '\"': case '\\': case '/': case 'b': case 'f': case 'n': case 'r': case 't': d->i++; break; case 'u': hi = 0; lo = 0; d->i++; if(d->i + 4 >= d->len) { return 0; } hi = int_from_hex(&(d->u[d->i])); if(hi < 0) { return 0; } d->i += 4; if(hi >= 0xD800 && hi < 0xDC00) { if(d->i + 6 >= d->len) { return 0; } if(d->p[d->i++] != '\\') { return 0; } else if(d->p[d->i++] != 'u') { return 0; } lo = int_from_hex(&(d->u[d->i])); if(lo < 0) { return 0; } hi = unicode_from_pair(hi, lo); if(hi < 0) { return 0; } } hi = utf8_len(hi); if(hi < 0) { return 0; } if(lo == 0) { num_escapes += 5 - hi; } else { num_escapes += 11 - hi; } break; default: return 0; } } else if(d->u[d->i] < 0x80) { d->i++; } else { ulen = utf8_validate(&(d->u[d->i]), d->len - d->i); if(ulen < 0) { return 0; } d->i += ulen; } } // The goto above ensures that we only // hit this when a string is not terminated // correctly. return 0; parse: if(!has_escape) { *value = enif_make_sub_binary(d->env, d->arg, st, (d->i - st - 1)); return 1; } hi = 0; lo = 0; ulen = (d->i - 1) - st - num_escapes; chrbuf = (char*) enif_make_new_binary(d->env, ulen, value); chrpos = 0; ui = st; while(ui < d->i - 1) { if(d->p[ui] != '\\') { chrbuf[chrpos++] = d->p[ui++]; continue; } ui++; switch(d->p[ui]) { case '\"': case '\\': case '/': chrbuf[chrpos++] = d->p[ui]; ui++; break; case 'b': chrbuf[chrpos++] = '\b'; ui++; break; case 'f': chrbuf[chrpos++] = '\f'; ui++; break; case 'n': chrbuf[chrpos++] = '\n'; ui++; break; case 'r': chrbuf[chrpos++] = '\r'; ui++; break; case 't': chrbuf[chrpos++] = '\t'; ui++; break; case 'u': ui++; hi = int_from_hex(&(d->u[ui])); if(hi < 0) { return 0; } if(hi >= 0xD800 && hi < 0xDC00) { lo = int_from_hex(&(d->u[ui+6])); if(lo < 0) { return 0; } hi = unicode_from_pair(hi, lo); ui += 10; } else { ui += 4; } hi = unicode_to_utf8(hi, (unsigned char*) chrbuf+chrpos); if(hi < 0) { return 0; } chrpos += hi; break; default: return 0; } } return 1; }
ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ DH *dh_params = NULL; int mpint; /* 0 or 4 */ { ERL_NIF_TERM head, tail; BIGNUM *dh_p = NULL, *dh_g = NULL, *priv_key_in = NULL; unsigned long len = 0; if (!(get_bn_from_bin(env, argv[0], &priv_key_in) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) || !enif_get_ulong(env, argv[3], &len) /* Load dh_params with values to use by the generator. Mem mgmnt transfered from dh_p etc to dh_params */ || !(dh_params = DH_new()) || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) ) { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } if (len) { if (len < BN_num_bits(dh_p)) DH_set_length(dh_params, len); else { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } } } #ifdef HAS_EVP_PKEY_CTX { EVP_PKEY_CTX *ctx; EVP_PKEY *dhkey, *params; int success; params = EVP_PKEY_new(); success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ DH_free(dh_params); /* ...dh_params (and params) must be freed */ if (!success) return atom_error; ctx = EVP_PKEY_CTX_new(params, NULL); EVP_PKEY_free(params); if (!ctx) { return atom_error; } if (!EVP_PKEY_keygen_init(ctx)) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } dhkey = EVP_PKEY_new(); if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ /*... generated key is written to ppkey." (=last arg) */ /* EVP_PKEY_CTX_free(ctx); */ /* EVP_PKEY_free(dhkey); */ return atom_error; } dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ EVP_PKEY_free(dhkey); if (!dh_params) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } EVP_PKEY_CTX_free(ctx); } #else if (!DH_generate_key(dh_params)) return atom_error; #endif { unsigned char *pub_ptr, *prv_ptr; int pub_len, prv_len; ERL_NIF_TERM ret_pub, ret_prv; const BIGNUM *pub_key_gen, *priv_key_gen; DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. "The values point to the internal representation of the public key and private key values. This memory should not be freed directly." says man */ pub_len = BN_num_bytes(pub_key_gen); prv_len = BN_num_bytes(priv_key_gen); pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); if (mpint) { put_int32(pub_ptr, pub_len); pub_ptr += 4; put_int32(prv_ptr, prv_len); prv_ptr += 4; } BN_bn2bin(pub_key_gen, pub_ptr); BN_bn2bin(priv_key_gen, prv_ptr); ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); DH_free(dh_params); return enif_make_tuple2(env, ret_pub, ret_prv); } }
static ERL_NIF_TERM x509_make_cert_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { int expiry, serial; ASN1_INTEGER *asn1serial = NULL; BIGNUM *bn_rsa_genkey=NULL; BIO *bio_signing_private=NULL, *bio_issuer_cert = NULL, *bio_newcert_public = NULL; BIO *bio_x509=NULL; char *issuer_cert_pem=NULL; X509 *pX509 = NULL; X509 *pIssuerX509 = NULL; X509_NAME *pX509Name = NULL; X509_NAME *pIssuerName = NULL; x509_subject_entry *subject_entries; int num_subject_entries; int iret = 0; RSA *rsa=NULL; unsigned long f4=RSA_F4; unsigned args_len=-1; char *signing_keys[2], *cert_keys[2]; ERL_NIF_TERM tail, *arg_terms=NULL; int idx; ERL_NIF_TERM ret, x509term; int x509len; unsigned char *x509data; EVP_PKEY *evp_signing_private = EVP_PKEY_new(); EVP_PKEY *evp_newcert_public_key = EVP_PKEY_new(); /* set RSA key gen type */ bn_rsa_genkey = BN_new(); BN_set_word(bn_rsa_genkey, f4); // // 1. stick subject of CA cert into NewCert // 2. stick public key of NewKeypair into NewCert // 3. sign NewCert with CA keypair /* Should be 6 elements in the list of X509 parameters. We'll check each */ if(!enif_get_list_length(env, argv[0], &args_len) || args_len != 6 || NULL == (arg_terms = (ERL_NIF_TERM*)malloc(args_len * sizeof(ERL_NIF_TERM)))) return enif_make_badarg(env); enif_get_list_cell(env, argv[0], &arg_terms[0], &tail); for(idx=1; idx<args_len; idx++){ if(!enif_get_list_cell(env, tail, &arg_terms[idx], &tail)){ free(arg_terms); return enif_make_badarg(env); } } idx=0; /* get the signing private key */ x509_parse_keypair(env, "signing_key", arg_terms[idx++], signing_keys); /* get the issuer cert */ x509_parse_issuer_cert(env, arg_terms[idx++], &issuer_cert_pem); /* get the soon-to-be cert's public key */ x509_parse_keypair(env, "newcert_public_key", arg_terms[idx++], cert_keys); /* get the subject */ x509_parse_subject(env, arg_terms[idx++], &num_subject_entries, &subject_entries); /* get the serial number */ x509_parse_int_tuple(env, arg_terms[idx++], "serial", &serial); /* get the expiry */ x509_parse_int_tuple(env, arg_terms[idx++], "expiry", &expiry); /* work the OpenSSL cert creation magic */ if ((bio_signing_private = BIO_new_mem_buf(signing_keys[1], -1)) && (rsa = PEM_read_bio_RSAPrivateKey(bio_signing_private, NULL, NULL, NULL)) && (iret = EVP_PKEY_assign_RSA(evp_signing_private, rsa)) && (bio_newcert_public = BIO_new_mem_buf(cert_keys[0], -1)) && (evp_newcert_public_key = PEM_read_bio_PUBKEY(bio_newcert_public, NULL, NULL, NULL)) && (bio_issuer_cert = BIO_new_mem_buf(issuer_cert_pem, -1)) && (pIssuerX509 = PEM_read_bio_X509(bio_issuer_cert, NULL, NULL, NULL)) && (pX509 = X509_new())) { /* if we've managed to generate a key and allocate structure memory, set X509 fields */ asn1serial = ASN1_INTEGER_new(); X509_set_version(pX509, 2); /* cert_helper uses '3' here */ ASN1_INTEGER_set(asn1serial, serial); X509_set_serialNumber(pX509, asn1serial); X509_gmtime_adj(X509_get_notBefore(pX509),0); X509_gmtime_adj(X509_get_notAfter(pX509),(long)60*60*24*expiry); X509_set_pubkey(pX509, evp_newcert_public_key); pX509Name = X509_get_subject_name(pX509); while(--num_subject_entries >= 0){ X509_NAME_add_entry_by_txt(pX509Name, (subject_entries[num_subject_entries]).name, MBSTRING_ASC, (unsigned char*)(subject_entries[num_subject_entries]).value, -1, -1, 0); } pIssuerName = X509_get_issuer_name(pIssuerX509); X509_set_issuer_name(pX509, pIssuerName); X509_sign(pX509, evp_signing_private, digest); bio_x509 = BIO_new(BIO_s_mem()); PEM_write_bio_X509(bio_x509, pX509); x509len = BIO_get_mem_data(bio_x509, &x509data); memcpy(enif_make_new_binary(env, x509len, &x509term), x509data, x509len); ret = enif_make_tuple2(env, atom_x509_cert, x509term); } done: if(arg_terms) free(arg_terms); free_keys(signing_keys); free_keys(cert_keys); free_subject_entries(num_subject_entries, subject_entries); if(pX509) X509_free(pX509); if(pIssuerX509) X509_free(pIssuerX509); if(issuer_cert_pem) free(issuer_cert_pem); if(bio_issuer_cert) { BIO_set_close(bio_issuer_cert, BIO_NOCLOSE); BIO_free_all(bio_issuer_cert); } if(bio_signing_private) { BIO_set_close(bio_signing_private, BIO_NOCLOSE); BIO_free_all(bio_signing_private); } if(bio_newcert_public) { BIO_set_close(bio_newcert_public, BIO_NOCLOSE); BIO_free_all(bio_newcert_public); } if(bio_x509) BIO_free_all(bio_x509); if(asn1serial) ASN1_INTEGER_free(asn1serial); if(bn_rsa_genkey) BN_free(bn_rsa_genkey); if(rsa) RSA_free(rsa); return ret; }
static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM ret; ERL_NIF_TERM private_keyterm, public_keyterm; BIO *bio_private_pem=NULL, *bio_public_pem=NULL; RSA *rsa = NULL; BIGNUM *bn_rsa_genkey=NULL; int rsa_keylen=-1; int private_pemlen, public_pemlen; unsigned long f4=RSA_F4; int dlen; /* BUGBUG: Need better validation of key length here [cb] */ if (!enif_get_int(env, argv[0], &rsa_keylen)) { return enif_make_badarg(env); } /* Do all allocations and fail function call if any single alloc failed */ rsa = RSA_new(); bn_rsa_genkey = BN_new(); bio_private_pem = BIO_new(BIO_s_mem()); bio_public_pem = BIO_new(BIO_s_mem()); /* Do actual OpenSSL work */ if(rsa && bn_rsa_genkey && bio_private_pem && bio_public_pem){ BN_set_word(bn_rsa_genkey, f4); if (RSA_generate_key_ex(rsa, rsa_keylen, bn_rsa_genkey, NULL)) { unsigned char *private_pemdata; unsigned char *public_pemdata; PEM_write_bio_RSA_PUBKEY(bio_public_pem,rsa); PEM_write_bio_RSAPrivateKey(bio_private_pem,rsa,NULL,NULL,0,NULL,NULL); private_pemlen = BIO_get_mem_data(bio_private_pem, &private_pemdata); public_pemlen = BIO_get_mem_data(bio_public_pem, &public_pemdata); dlen = sizeof(int)+private_pemlen+sizeof(int)+public_pemlen; private_pemdata[private_pemlen]=0; public_pemdata[public_pemlen]=0; memcpy(enif_make_new_binary(env, private_pemlen, &private_keyterm), private_pemdata, private_pemlen); memcpy(enif_make_new_binary(env, public_pemlen, &public_keyterm), public_pemdata, public_pemlen); ret = enif_make_tuple3(env, atom_ok, public_keyterm, private_keyterm); } else { ret = enif_make_tuple2(env, atom_error, atom_bad_keylen); } } else { ret = enif_make_tuple2(env, atom_error, atom_bad_ssl_init); } /* dealloc */ if(bio_private_pem) BIO_free_all(bio_private_pem); if(bio_public_pem) BIO_free_all(bio_public_pem); if(bn_rsa_genkey) BN_free(bn_rsa_genkey); if(rsa) RSA_free(rsa); return ret; }
ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Base,Exponent,Modulo,bin_hdr) */ BIGNUM *bn_base = NULL, *bn_exponent = NULL, *bn_modulo = NULL, *bn_result = NULL; BN_CTX *bn_ctx = NULL; unsigned char* ptr; int dlen; unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */ unsigned extra_byte; ERL_NIF_TERM ret; ASSERT(argc == 4); if (!get_bn_from_bin(env, argv[0], &bn_base)) goto bad_arg; if (!get_bn_from_bin(env, argv[1], &bn_exponent)) goto bad_arg; if (!get_bn_from_bin(env, argv[2], &bn_modulo)) goto bad_arg; if (!enif_get_uint(env, argv[3], &bin_hdr)) goto bad_arg; if (bin_hdr != 0 && bin_hdr != 4) goto bad_arg; if ((bn_result = BN_new()) == NULL) goto err; if ((bn_ctx = BN_CTX_new()) == NULL) goto err; if (!BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx)) goto err; dlen = BN_num_bytes(bn_result); if (dlen < 0 || dlen > INT_MAX / 8) goto bad_arg; extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen * 8 - 1); if ((ptr = enif_make_new_binary(env, bin_hdr + extra_byte + (unsigned int)dlen, &ret)) == NULL) goto err; if (bin_hdr) { put_uint32(ptr, extra_byte + (unsigned int)dlen); ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */ ptr += bin_hdr + extra_byte; } BN_bn2bin(bn_result, ptr); goto done; bad_arg: err: ret = enif_make_badarg(env); done: if (bn_base) BN_free(bn_base); if (bn_exponent) BN_free(bn_exponent); if (bn_modulo) BN_free(bn_modulo); if (bn_result) BN_free(bn_result); if (bn_ctx) BN_CTX_free(bn_ctx); return ret; }