Skip to content

Commit 2e401b3

Browse files
committed
feat(pkey) support pass in ctrl str options
1 parent 12f5209 commit 2e401b3

File tree

5 files changed

+328
-82
lines changed

5 files changed

+328
-82
lines changed

README.md

+88-26
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ A module to provide error messages.
570570
### err.format_error
571571

572572
**syntax**: *msg = err.format_error(ctx_msg?, return_code?, all_errors?)*
573+
573574
**syntax**: *msg = err.format_all_errors(ctx_msg?, return_code?)*
574575

575576
Return the latest error message from the last error code. Errors are formatted as:
@@ -905,6 +906,26 @@ local key, err = pkey.new({
905906
})
906907
```
907908

909+
It's also possible to pass raw pkeyopt control strings in `config` table as used in the `genpkey` CLI program.
910+
See [openssl-genpkey(1)](https://www.openssl.org/docs/man3.0/man1/openssl-genpkey.html) for a list of options.
911+
912+
For example:
913+
914+
```lua
915+
pkey.new({
916+
type = 'RSA',
917+
bits = 2048,
918+
exp = 65537,
919+
})
920+
-- is same as
921+
pkey.new({
922+
type = 'RSA',
923+
exp = 65537,
924+
"rsa_keygen_bits:4096",
925+
})
926+
927+
```
928+
908929

909930
[Back to TOC](#table-of-contents)
910931

@@ -956,6 +977,9 @@ local pem, err = pkey.paramgen({
956977
})
957978
```
958979

980+
It's also possible to pass raw pkeyopt control strings in `config` table as used in the `genpkey` CLI program.
981+
See [openssl-genpkey(1)](https://www.openssl.org/docs/man3.0/man1/openssl-genpkey.html) for a list of options.
982+
959983
[Back to TOC](#table-of-contents)
960984

961985
### pkey:get_provider_name
@@ -1110,10 +1134,20 @@ to use when signing. When `md_alg` is undefined, for RSA and EC keys, this funct
11101134
by default. For Ed25519 or Ed448 keys, this function does a PureEdDSA signing,
11111135
no message digest should be specified and will not be used.
11121136

1113-
`opts` is a table that accepts additional parameters.
1137+
For RSA key, it's also possible to specify `padding` scheme with following choices:
11141138

1115-
For RSA key, it's also possible to specify `padding` scheme. The choice of values are same
1116-
as those in [pkey:encrypt](#pkeyencrypt). When `padding` is `RSA_PKCS1_PSS_PADDING`, it's
1139+
```lua
1140+
pkey.PADDINGS = {
1141+
RSA_PKCS1_PADDING = 1,
1142+
RSA_SSLV23_PADDING = 2,
1143+
RSA_NO_PADDING = 3,
1144+
RSA_PKCS1_OAEP_PADDING = 4,
1145+
RSA_X931_PADDING = 5, -- sign only
1146+
RSA_PKCS1_PSS_PADDING = 6, -- sign and verify only
1147+
}
1148+
```
1149+
1150+
When `padding` is `RSA_PKCS1_PSS_PADDING`, it's
11171151
possible to specify PSS salt length by setting `opts.pss_saltlen`.
11181152

11191153
For EC key, this function does a ECDSA signing.
@@ -1125,6 +1159,32 @@ is encoded in ASN.1 DER format. If the `opts` table contains a `ecdsa_use_raw` f
11251159
a true value, a binary with just the concatenation of binary representation `pr` and `ps` is returned.
11261160
This is useful for example to send the signature as JWS.
11271161

1162+
`opts` is a table that accepts additional parameters with following choices:
1163+
1164+
```
1165+
{
1166+
pss_saltlen, -- For PSS mode only this option specifies the salt length.
1167+
mgf1_md, -- For PSS and OAEP padding sets the MGF1 digest. If the MGF1 digest is not explicitly set in PSS mode then the signing digest is used.
1168+
oaep_md, -- The digest used for the OAEP hash function. If not explicitly set then SHA1 is used.
1169+
}
1170+
```
1171+
1172+
It's also possible to pass raw pkeyopt control strings as used in the `pkeyutl` CLI program. This lets user pass in options that
1173+
are not explictly supported as parameters above.
1174+
See [openssl-pkeyutl(1)](https://www.openssl.org/docs/manmaster/man1/openssl-pkeyutl.html) for a list of options.
1175+
1176+
```lua
1177+
pk:sign(message, nil, pk.PADDINGS.RSA_PKCS1_OAEP_PADDING, {
1178+
oaep_md = "sha256",
1179+
})
1180+
-- is same as
1181+
pk:sign(message, nil, nil, {
1182+
"rsa_padding_mode:oaep",
1183+
"rsa_oaep_md:sha256",
1184+
})
1185+
-- in pkeyutl CLI the above is equivalent to: `openssl pkeyutl -sign -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256
1186+
```
1187+
11281188
[Back to TOC](#table-of-contents)
11291189

11301190
### pkey:verify
@@ -1147,17 +1207,19 @@ to use when verifying. When `md_alg` is undefined, for RSA and EC keys, this fun
11471207
by default. For Ed25519 or Ed448 keys, this function does a PureEdDSA verification,
11481208
no message digest should be specified and will not be used.
11491209

1150-
`opts` is a table that accepts additional parameters.
1151-
1152-
For RSA key, it's also possible to specify `padding` scheme. The choice of values are same
1153-
as those in [pkey:encrypt](#pkeyencrypt). When `padding` is `RSA_PKCS1_PSS_PADDING`, it's
1210+
When key is a RSA key, the function accepts an optional argument `padding` which choices
1211+
of values are same as those in [pkey:sign](#pkeysign). When `padding` is `RSA_PKCS1_PSS_PADDING`, it's
11541212
possible to specify PSS salt length by setting `opts.pss_saltlen`.
11551213

11561214
For EC key, this function does a ECDSA verification. Normally, the ECDSA signature
11571215
should be encoded in ASN.1 DER format. If the `opts` table contains a `ecdsa_use_raw` field with
11581216
a true value, this library treat `signature` as concatenation of binary representation `pr` and `ps`.
11591217
This is useful for example to verify the signature as JWS.
11601218

1219+
`opts` is a table that accepts additional parameters which choices
1220+
of values are same as those in [pkey:sign](#pkeysign).
1221+
1222+
11611223
```lua
11621224
-- RSA and EC keys
11631225
local pk, err = require("resty.openssl.pkey").new()
@@ -1193,34 +1255,28 @@ ngx.say(ngx.encode_base64(signature))
11931255

11941256
### pkey:encrypt
11951257

1196-
**syntax**: *cipher_txt, err = pk:encrypt(txt, padding?)*
1258+
**syntax**: *cipher_txt, err = pk:encrypt(txt, padding?, opts?)*
11971259

11981260
Encrypts plain text `txt` with `pkey` instance, which must loaded a public key.
11991261

1200-
When key is a RSA key, the function accepts an optional second argument `padding` which can be:
1262+
The optional second argument `padding` has same meaning as in [pkey:sign](#pkeysign).
1263+
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
12011264

1202-
```lua
1203-
pkey.PADDINGS = {
1204-
RSA_PKCS1_PADDING = 1,
1205-
RSA_SSLV23_PADDING = 2,
1206-
RSA_NO_PADDING = 3,
1207-
RSA_PKCS1_OAEP_PADDING = 4,
1208-
RSA_X931_PADDING = 5,
1209-
RSA_PKCS1_PSS_PADDING = 6,
1210-
}
1211-
```
1265+
The third optional argument `opts` has same meaning as in [pkey:sign](#pkeysign).
12121266

1213-
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
12141267

12151268
[Back to TOC](#table-of-contents)
12161269

12171270
### pkey:decrypt
12181271

1219-
**syntax**: *txt, err = pk:decrypt(cipher_txt, padding?)*
1272+
**syntax**: *txt, err = pk:decrypt(cipher_txt, padding?, opts?)*
12201273

12211274
Decrypts cipher text `cipher_txt` with pkey instance, which must loaded a private key.
12221275

1223-
The optional second argument `padding` has same meaning in [pkey:encrypt](#pkeyencrypt).
1276+
The optional second argument `padding` has same meaning as in [pkey:sign](#pkeysign).
1277+
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
1278+
1279+
The third optional argument `opts` has same meaning as in [pkey:sign](#pkeysign).
12241280

12251281
```lua
12261282
local pkey = require("resty.openssl.pkey")
@@ -1239,11 +1295,14 @@ ngx.say(decrypted)
12391295

12401296
### pkey:sign_raw
12411297

1242-
**syntax**: *signature, err = pk:sign_raw(txt, padding?)*
1298+
**syntax**: *signature, err = pk:sign_raw(txt, padding?, opts?)*
12431299

12441300
Signs the cipher text `cipher_txt` with pkey instance, which must loaded a private key.
12451301

1246-
The optional second argument `padding` has same meaning in [pkey:encrypt](#pkeyencrypt).
1302+
The optional second argument `padding` has same meaning as in [pkey:sign](#pkeysign).
1303+
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
1304+
1305+
The third optional argument `opts` has same meaning as in [pkey:sign](#pkeysign).
12471306

12481307
This function may also be called "private encrypt" in some implementations like NodeJS or PHP.
12491308
Do note as the function names suggested, this function is not secure to be regarded as an encryption.
@@ -1257,12 +1316,15 @@ for an example.
12571316

12581317
### pkey:verify_recover
12591318

1260-
**syntax**: *txt, err = pk:verify_recover(signature, padding?)*
1319+
**syntax**: *txt, err = pk:verify_recover(signature, padding?, opts?)*
12611320

12621321
Verify the cipher text `signature` with pkey instance, which must loaded a public key, and also
12631322
returns the original text being signed. This operation is only supported by RSA key.
12641323

1265-
The optional second argument `padding` has same meaning in [pkey:encrypt](#pkeyencrypt).
1324+
The optional second argument `padding` has same meaning as in [pkey:sign](#pkeysign).
1325+
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
1326+
1327+
The third optional argument `opts` has same meaning as in [pkey:sign](#pkeysign).
12661328

12671329
This function may also be called "public decrypt" in some implementations like NodeJS or PHP.
12681330

lib/resty/openssl/include/evp.lua

+23-10
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,23 @@ local _M = {
4444
EVP_PKEY_X448 = C.OBJ_txt2nid("X448"),
4545
EVP_PKEY_ED448 = C.OBJ_txt2nid("ED448"),
4646

47-
EVP_PKEY_OP_PARAMGEN = bit.lshift(1, 1),
48-
EVP_PKEY_OP_KEYGEN = bit.lshift(1, 2),
49-
EVP_PKEY_OP_SIGN = bit.lshift(1, 3),
50-
EVP_PKEY_OP_VERIFY = bit.lshift(1, 4),
51-
EVP_PKEY_OP_DERIVE = OPENSSL_3X and bit.lshift(1, 12) or bit.lshift(1, 10),
47+
EVP_CTRL_AEAD_SET_IVLEN = 0x9,
48+
EVP_CTRL_AEAD_GET_TAG = 0x10,
49+
EVP_CTRL_AEAD_SET_TAG = 0x11,
5250

53-
EVP_PKEY_ALG_CTRL = EVP_PKEY_ALG_CTRL,
51+
-- remove EVP_PKEY_OP_* and EVP_PKEY_CTRL_* after openssl 1.1.1 support is dropped
52+
EVP_PKEY_OP_PARAMGEN = not OPENSSL_3X and bit.lshift(1, 1) or nil,
53+
EVP_PKEY_OP_KEYGEN = not OPENSSL_3X and bit.lshift(1, 2) or nil,
54+
EVP_PKEY_OP_SIGN = not OPENSSL_3X and bit.lshift(1, 3) or nil,
55+
EVP_PKEY_OP_VERIFY = not OPENSSL_3X and bit.lshift(1, 4) or nil,
56+
EVP_PKEY_OP_VERIFYRECOVER = not OPENSSL_3X and bit.lshift(1, 5) or nil,
57+
EVP_PKEY_OP_SIGNCTX = not OPENSSL_3X and bit.lshift(1, 6) or nil,
58+
EVP_PKEY_OP_VERIFYCTX = not OPENSSL_3X and bit.lshift(1, 7) or nil,
59+
EVP_PKEY_OP_ENCRYPT = not OPENSSL_3X and bit.lshift(1, 8) or nil,
60+
EVP_PKEY_OP_DECRYPT = not OPENSSL_3X and bit.lshift(1, 9) or nil,
61+
EVP_PKEY_OP_DERIVE = not OPENSSL_3X and bit.lshift(1, 10) or nil,
5462

63+
EVP_PKEY_ALG_CTRL = EVP_PKEY_ALG_CTRL,
5564

5665
EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN = EVP_PKEY_ALG_CTRL + 1,
5766
EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID = EVP_PKEY_ALG_CTRL + 1,
@@ -60,10 +69,8 @@ local _M = {
6069
EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP = EVP_PKEY_ALG_CTRL + 4,
6170
EVP_PKEY_CTRL_RSA_PADDING = EVP_PKEY_ALG_CTRL + 1,
6271
EVP_PKEY_CTRL_RSA_PSS_SALTLEN = EVP_PKEY_ALG_CTRL + 2,
63-
64-
EVP_CTRL_AEAD_SET_IVLEN = 0x9,
65-
EVP_CTRL_AEAD_GET_TAG = 0x10,
66-
EVP_CTRL_AEAD_SET_TAG = 0x11,
72+
EVP_PKEY_CTRL_RSA_MGF1_MD = EVP_PKEY_ALG_CTRL + 5,
73+
EVP_PKEY_CTRL_RSA_OAEP_MD = EVP_PKEY_ALG_CTRL + 9,
6774

6875
EVP_PKEY_CTRL_TLS_MD = EVP_PKEY_ALG_CTRL,
6976
EVP_PKEY_CTRL_TLS_SECRET = EVP_PKEY_ALG_CTRL + 1,
@@ -81,6 +88,12 @@ local _M = {
8188
EVP_PKEY_CTRL_SCRYPT_MAXMEM_BYTES = EVP_PKEY_ALG_CTRL + 13,
8289
}
8390

91+
if not OPENSSL_3X then
92+
_M.EVP_PKEY_OP_CRYPT = _M.EVP_PKEY_OP_ENCRYPT + _M.EVP_PKEY_OP_DECRYPT
93+
_M.EVP_PKEY_OP_SIG = _M.EVP_PKEY_OP_SIGN + _M.EVP_PKEY_OP_VERIFY + _M.EVP_PKEY_OP_VERIFYRECOVER +
94+
_M.EVP_PKEY_OP_SIGNCTX + _M.EVP_PKEY_OP_VERIFYCTX
95+
end
96+
8497
-- clean up error occurs during OBJ_txt2*
8598
C.ERR_clear_error()
8699

lib/resty/openssl/include/evp/pkey.lua

+43-6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ ffi.cdef [[
8181
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
8282
int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
8383
int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
84+
85+
int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
86+
const char *value);
8487
]]
8588

8689
local _M = {}
@@ -102,6 +105,10 @@ if OPENSSL_3X then
102105

103106
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad);
104107
int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int len);
108+
int EVP_PKEY_CTX_set_rsa_mgf1_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
109+
const char *mdprops);
110+
int EVP_PKEY_CTX_set_rsa_oaep_md_name(EVP_PKEY_CTX *ctx, const char *mdname,
111+
const char *mdprops);
105112

106113
int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits);
107114

@@ -121,6 +128,10 @@ if OPENSSL_3X then
121128
return C.EVP_PKEY_CTX_set_ec_param_enc(pctx, param_enc)
122129
end
123130

131+
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
132+
return C.EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, pbits)
133+
end
134+
124135
_M.EVP_PKEY_CTX_set_rsa_keygen_bits = function(pctx, mbits)
125136
return C.EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, mbits)
126137
end
@@ -134,8 +145,11 @@ if OPENSSL_3X then
134145
_M.EVP_PKEY_CTX_set_rsa_pss_saltlen = function(pctx, len)
135146
return C.EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, len)
136147
end
137-
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
138-
return C.EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx, pbits)
148+
_M.EVP_PKEY_CTX_set_rsa_mgf1_md_name = function(pctx, name ,props)
149+
return C.EVP_PKEY_CTX_set_rsa_mgf1_md_name(pctx, name, props)
150+
end
151+
_M.EVP_PKEY_CTX_set_rsa_oaep_md_name = function(pctx, name, props)
152+
return C.EVP_PKEY_CTX_set_rsa_oaep_md_name(pctx, name, props)
139153
end
140154

141155
else
@@ -154,6 +168,13 @@ else
154168
param_enc, nil)
155169
end
156170

171+
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
172+
return C.EVP_PKEY_CTX_ctrl(pctx,
173+
evp.EVP_PKEY_DH, evp.EVP_PKEY_OP_PARAMGEN,
174+
evp.EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN,
175+
pbits, nil)
176+
end
177+
157178
_M.EVP_PKEY_CTX_set_rsa_keygen_bits = function(pctx, mbits)
158179
return C.EVP_PKEY_CTX_ctrl(pctx,
159180
evp.EVP_PKEY_RSA,
@@ -183,11 +204,27 @@ else
183204
len, nil)
184205
end
185206

186-
_M.EVP_PKEY_CTX_set_dh_paramgen_prime_len = function(pctx, pbits)
207+
_M.EVP_PKEY_CTX_set_rsa_mgf1_md_name = function(pctx, name, _)
208+
local md = C.EVP_get_digestbyname(name)
209+
if not md then
210+
return -1, "unknown digest: " .. name
211+
end
187212
return C.EVP_PKEY_CTX_ctrl(pctx,
188-
evp.EVP_PKEY_DH, evp.EVP_PKEY_OP_PARAMGEN,
189-
evp.EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN,
190-
pbits, nil)
213+
evp.EVP_PKEY_RSA,
214+
evp.EVP_PKEY_OP_SIG + evp.EVP_PKEY_OP_TYPE_CRYPT,
215+
evp.EVP_PKEY_CTRL_RSA_MGF1_MD,
216+
0, ffi.cast("void *", md))
217+
end
218+
_M.EVP_PKEY_CTX_set_rsa_oaep_md_name = function(pctx, name, _)
219+
local md = C.EVP_get_digestbyname(name)
220+
if not md then
221+
return -1, "unknown digest: " .. name
222+
end
223+
return C.EVP_PKEY_CTX_ctrl(pctx,
224+
evp.EVP_PKEY_RSA,
225+
evp.EVP_PKEY_OP_CRYPT,
226+
evp.EVP_PKEY_CTRL_RSA_OAEP_MD,
227+
0, ffi.cast("void *", md))
191228
end
192229
end
193230

0 commit comments

Comments
 (0)