const EVP_MD* get_digest(lua_State* L, int idx, const char* def_alg) { const EVP_MD* md = NULL; switch (lua_type(L, idx)) { case LUA_TSTRING: md = EVP_get_digestbyname(lua_tostring(L, idx)); break; case LUA_TNUMBER: md = EVP_get_digestbynid(lua_tointeger(L, idx)); break; case LUA_TUSERDATA: if (auxiliar_getclassudata(L, "openssl.asn1_object", idx)) md = EVP_get_digestbyobj(CHECK_OBJECT(idx, ASN1_OBJECT, "openssl.asn1_object")); else if (auxiliar_getclassudata(L, "openssl.evp_digest", idx)) md = CHECK_OBJECT(idx, EVP_MD, "openssl.evp_digest"); break; case LUA_TNONE: case LUA_TNIL: if (def_alg != NULL) md = EVP_get_digestbyname(def_alg); break; } if (md==NULL) { luaL_argerror(L, idx, "must be a string, NID number or asn1_object identity digest method"); } return md; }
const EVP_CIPHER* get_cipher(lua_State*L, int idx, const char* def_alg) { const EVP_CIPHER* cipher = NULL; switch (lua_type(L, idx)) { case LUA_TSTRING: cipher = EVP_get_cipherbyname(lua_tostring(L, idx)); break; case LUA_TNUMBER: cipher = EVP_get_cipherbynid(lua_tointeger(L, idx)); break; case LUA_TUSERDATA: if (auxiliar_getclassudata(L, "openssl.asn1_object", idx)) cipher = EVP_get_cipherbyobj(CHECK_OBJECT(idx, ASN1_OBJECT, "openssl.asn1_object")); else if (auxiliar_getclassudata(L, "openssl.evp_cipher", idx)) cipher = CHECK_OBJECT(idx, EVP_CIPHER, "openssl.evp_cipher"); break; case LUA_TNONE: case LUA_TNIL: if (def_alg != NULL) cipher = EVP_get_cipherbyname(def_alg); break; } if (cipher==NULL) luaL_argerror(L, idx, "must be a string, NID number or asn1_object identity cipher method"); return cipher; }
/*** create or generate a new x509_req object. Note if not give evp_pkey, will create a new x509_req object,or will generate a signed x509_req object. @function new @tparam[opt] x509_name subject subject name set to x509_req @tparam[opt] stack_of_x509_extension extensions add to x509_req @tparam[opt] stack_of_x509_attribute attributes add to x509_req @tparam[opt] evp_pkey pkey private key sign the x509_req, and set as public key @tparam[opt='sha1WithRSAEncryption'] evp_digest|string md_alg, only used when pkey exist, and should fellow pkey @treturn x509_req certificate sign request object @see x509_req */ static LUA_FUNCTION(openssl_csr_new) { X509_REQ *csr = X509_REQ_new(); int i; int n = lua_gettop(L); int ret = X509_REQ_set_version(csr, 0L); for (i = 1; ret == 1 && i <= n; i++) { luaL_argcheck(L, auxiliar_getclassudata(L, "openssl.x509_name", i) || auxiliar_getclassudata(L, "openssl.evp_pkey", i), i, "must be x509_name or evp_pkey"); if (auxiliar_getclassudata(L, "openssl.x509_name", i)) { X509_NAME * subject = CHECK_OBJECT(i, X509_NAME, "openssl.x509_name"); ret = X509_REQ_set_subject_name(csr, subject); } if (auxiliar_getclassudata(L, "openssl.evp_pkey", i)) { EVP_PKEY *pkey; const EVP_MD *md; luaL_argcheck(L, i == n || i == n - 1, i, "must is evp_pkey object"); pkey = CHECK_OBJECT(i, EVP_PKEY, "openssl.evp_pkey"); if (i == n - 1) md = get_digest(L, n, NULL); else md = EVP_get_digestbyname("sha256"); ret = X509_REQ_set_pubkey(csr, pkey); if (ret == 1) { ret = X509_REQ_sign(csr, pkey, md); if (ret > 0) ret = 1; } break; } }; if (ret == 1) PUSH_OBJECT(csr, "openssl.x509_req"); else { X509_REQ_free(csr); return openssl_pushresult(L, ret); } return 1; }
/*** add attribute to x509_req object @function attribute @tparam x509_attribute attribute attribute to add @treturn boolean result */ static LUA_FUNCTION(openssl_csr_attribute) { X509_REQ *csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req"); if (auxiliar_getclassudata(L, "openssl.x509_attribute", 2)) { X509_ATTRIBUTE *attr = CHECK_OBJECT(2, X509_ATTRIBUTE, "openssl.x509_attribute"); int ret = X509_REQ_add1_attr(csr, attr); return openssl_pushresult(L, ret); } else if (lua_isnumber(L, 2)) { int loc = luaL_checkint(L, 2); X509_ATTRIBUTE *attr = NULL; if (lua_isnone(L, 3)) { attr = X509_REQ_get_attr(csr, loc); attr = X509_ATTRIBUTE_dup(attr); } else if (lua_isnil(L, 3)) { attr = X509_REQ_delete_attr(csr, loc); } if (attr) { PUSH_OBJECT(attr, "openssl.x509_attribute"); } else lua_pushnil(L); return 1; } else if (lua_istable(L, 2)) { int i; int ret = 1; int n = lua_rawlen(L, 2); for (i = 1; ret == 1 && i <= n; i++) { X509_ATTRIBUTE *attr; lua_rawgeti(L, 2, i); attr = NULL; if (lua_istable(L, -1)) { attr = openssl_new_xattribute(L, &attr, -1, NULL); ret = X509_REQ_add1_attr(csr, attr); X509_ATTRIBUTE_free(attr); } else { attr = CHECK_OBJECT(-1, X509_ATTRIBUTE, "openssl.x509_attribute"); ret = X509_REQ_add1_attr(csr, attr); } lua_pop(L, 1); } openssl_pushresult(L, ret); return 1; } return 0; }
/*-------------------------------------------------------------------------*\ * Return userdata pointer if object belongs to a given class, abort with * error otherwise \*-------------------------------------------------------------------------*/ void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { void *data = auxiliar_getclassudata(L, classname, objidx); if (!data) { char msg[45]; sprintf(msg, "%.35s expected", classname); luaL_argerror(L, objidx, msg); } return data; }
BIO* load_bio_object(lua_State* L, int idx) { BIO* bio = NULL; if (lua_isstring(L, idx)) { size_t l = 0; const char* ctx = lua_tolstring(L, idx, &l); /* read only */ bio = (BIO*)BIO_new_mem_buf((void*)ctx, l); } else if (auxiliar_getclassudata(L, "openssl.bio", idx)) { bio = CHECK_OBJECT(idx, BIO, "openssl.bio"); BIO_up_ref(bio); } else luaL_argerror(L, idx, "only support string or openssl.bio"); return bio; }
/*** sign x509_req object @function sign @tparam evp_pkey pkey private key which to sign x509_req object @tparam number|string|evp_md md message digest alg used to sign @treturn boolean result true for suceess */ static LUA_FUNCTION(openssl_csr_sign) { X509_REQ * csr = CHECK_OBJECT(1, X509_REQ, "openssl.x509_req"); EVP_PKEY *pubkey = X509_REQ_get_pubkey(csr); if (auxiliar_getclassudata(L, "openssl.evp_pkey", 2)) { EVP_PKEY *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey"); const EVP_MD* md = get_digest(L, 3, "sha256"); int ret = 1; if (pubkey == NULL) { BIO* bio = BIO_new(BIO_s_mem()); if ((ret = i2d_PUBKEY_bio(bio, pkey)) == 1) { pubkey = d2i_PUBKEY_bio(bio, NULL); if (pubkey) { ret = X509_REQ_set_pubkey(csr, pubkey); EVP_PKEY_free(pubkey); } else { ret = 0; } } BIO_free(bio); } else { EVP_PKEY_free(pubkey); } if (ret == 1) ret = X509_REQ_sign(csr, pkey, md); return openssl_pushresult(L, ret); } else if (lua_isstring(L, 2)) { size_t siglen; unsigned char* sigdata = (unsigned char*)luaL_checklstring(L, 2, &siglen); const EVP_MD* md = get_digest(L, 3, NULL); ASN1_BIT_STRING *sig = NULL; X509_ALGOR *alg = NULL; luaL_argcheck(L, pubkey != NULL, 1, "has not set public key!!!"); X509_REQ_get0_signature(csr, (const ASN1_BIT_STRING **)&sig, (const X509_ALGOR **)&alg); /* (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) ? V_ASN1_NULL : V_ASN1_UNDEF, */ X509_ALGOR_set0((X509_ALGOR *)alg, OBJ_nid2obj(EVP_MD_pkey_type(md)), V_ASN1_NULL, NULL); ASN1_BIT_STRING_set((ASN1_BIT_STRING *)sig, sigdata, siglen); /* * In the interests of compatibility, I'll make sure that the bit string * has a 'not-used bits' value of 0 */ sig->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); sig->flags |= ASN1_STRING_FLAG_BITS_LEFT; lua_pushboolean(L, 1); return 1; } else { int inl; unsigned char* tosign = NULL; luaL_argcheck(L, pubkey != NULL, 1, "has not set public key!!!"); inl = i2d_re_X509_REQ_tbs(csr, &tosign); if (inl > 0 && tosign) { lua_pushlstring(L, (const char*)tosign, inl); OPENSSL_free(tosign); return 1; } return openssl_pushresult(L, 0); } }