Skip to content

Commit f5ed2a7

Browse files
committed
pkcs12: add PKCS12#set_mac
Add a binding for PKCS12_set_mac() to set MAC parameters and (re-)calculate MAC for the content. This allows generating PKCS #12 with consistent MAC parameters with different OpenSSL versions. OpenSSL 3.0 changed the default hash function used for HMAC and the KDF from SHA-1 to SHA-256. Fixes: #772
1 parent 3b3c950 commit f5ed2a7

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

ext/openssl/ossl_pkcs12.c

+43
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,48 @@ ossl_pkcs12_to_der(VALUE self)
251251
return str;
252252
}
253253

254+
/*
255+
* call-seq:
256+
* pkcs12.set_mac(pass, salt = nil, iter = nil, md_type = nil)
257+
*
258+
* Sets MAC parameters and generates MAC over the PKCS #12 structure.
259+
*
260+
* This method uses HMAC and the PKCS #12 specific password-based KDF as
261+
* specified in the original PKCS #12.
262+
*
263+
* See also the man page PKCS12_set_mac(3).
264+
*
265+
* Added in version 3.3.0.
266+
*/
267+
static VALUE
268+
pkcs12_set_mac(int argc, VALUE *argv, VALUE self)
269+
{
270+
PKCS12 *p12;
271+
VALUE pass, salt, iter, md_name;
272+
int iter_i = 0;
273+
const EVP_MD *md_type = NULL;
274+
275+
rb_scan_args(argc, argv, "13", &pass, &salt, &iter, &md_name);
276+
rb_check_frozen(self);
277+
GetPKCS12(self, p12);
278+
279+
StringValue(pass);
280+
if (!NIL_P(salt))
281+
StringValue(salt);
282+
if (!NIL_P(iter))
283+
iter_i = NUM2INT(iter);
284+
if (!NIL_P(md_name))
285+
md_type = ossl_evp_get_digestbyname(md_name);
286+
287+
if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass),
288+
!NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL,
289+
!NIL_P(salt) ? RSTRING_LENINT(salt) : 0,
290+
iter_i, md_type))
291+
ossl_raise(ePKCS12Error, "PKCS12_set_mac");
292+
293+
return Qnil;
294+
}
295+
254296
void
255297
Init_ossl_pkcs12(void)
256298
{
@@ -276,6 +318,7 @@ Init_ossl_pkcs12(void)
276318
rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse);
277319
rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1);
278320
rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0);
321+
rb_define_method(cPKCS12, "set_mac", pkcs12_set_mac, -1);
279322

280323
/* MSIE specific PKCS12 key usage extensions */
281324
rb_define_const(cPKCS12, "KEY_EX", INT2NUM(KEY_EX));

test/openssl/test_pkcs12.rb

+42
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,48 @@ def test_dup
337337
)
338338
assert_equal p12.to_der, p12.dup.to_der
339339
end
340+
341+
def test_set_mac_pkcs12kdf
342+
p12 = OpenSSL::PKCS12.create(
343+
"pass",
344+
"name",
345+
@mykey,
346+
@mycert,
347+
nil,
348+
nil,
349+
nil,
350+
nil,
351+
1234, # mac_iter
352+
nil,
353+
)
354+
macdata = macdata(p12)
355+
# Depends on the OpenSSL version: SHA256 in OpenSSL >= 3.0
356+
assert_include ["SHA1", "SHA256"], macdata[:mac_algo]
357+
assert_equal 1234, macdata[:iter]
358+
359+
p12.set_mac("pass", "macsalt", 2345, "SHA384")
360+
macdata = macdata(p12)
361+
assert_equal "SHA384", macdata[:mac_algo]
362+
assert_equal "macsalt", macdata[:salt]
363+
assert_equal 2345, macdata[:iter]
364+
assert_equal @mykey.to_der, OpenSSL::PKCS12.new(p12.to_der, "pass").key.to_der
365+
end
366+
367+
private
368+
369+
def macdata(p12)
370+
# See RFC 7292
371+
asn1 = OpenSSL::ASN1.decode(p12.to_der)
372+
macdata = asn1.value[2]
373+
mac = macdata.value[0]
374+
mac_algo = mac.value[0].value[0].value
375+
_mac_params = mac.value[0].value[1]
376+
{
377+
mac_algo: mac_algo,
378+
salt: macdata.value[1].value,
379+
iter: macdata.value[2]&.value,
380+
}
381+
end
340382
end
341383
end
342384

0 commit comments

Comments
 (0)