Subject: | [PATCH] add setPrivateKeyPkcs12 |
Hello,
please find enclosed patch that adds new function setPrivateKeyPkcs12 which loads private key + corresponding cert from PKCS12 file.
The patch includes also test and documentation.
Regards,
Karel
Subject: | setPrivateKeyPkcs12.diff |
diff -ru Crypt-SMIME-0.16_original/SMIME.xs Crypt-SMIME-0.16/SMIME.xs
--- Crypt-SMIME-0.16_original/SMIME.xs 2015-10-05 03:48:07.000000000 +0200
+++ Crypt-SMIME-0.16/SMIME.xs 2016-06-21 00:02:35.814664200 +0200
@@ -3,6 +3,7 @@
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
+#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
@@ -485,6 +486,43 @@
OUTPUT:
RETVAL
+SV*
+setPrivateKeyPkcs12(Crypt_SMIME this, SV* pkcs12, char* password = "")
+ PROTOTYPE: $$$;$
+ PREINIT:
+ BIO *bio;
+ PKCS12 *p12;
+ int success = 0;
+ CODE:
+ if (this->priv_cert) {
+ X509_free(this->priv_cert);
+ this->priv_cert = NULL;
+ }
+ if (this->priv_key) {
+ EVP_PKEY_free(this->priv_key);
+ this->priv_key = NULL;
+ }
+
+ if (SvOK(pkcs12)) {
+ if (bio = BIO_new_mem_buf(SvPV_nolen(pkcs12), SvCUR(pkcs12))) {
+ if (p12 = d2i_PKCS12_bio(bio, NULL)) {
+ success = PKCS12_parse(p12, password, &this->priv_key, &this->priv_cert, NULL);
+ }
+ BIO_free(bio);
+ }
+ }
+
+ if (!success || this->priv_key == NULL || this->priv_cert == NULL) {
+ OPENSSL_CROAK("Crypt::SMIME#setPrivateKeyPkcs12: failed");
+ }
+ this->priv_key_is_tainted = SvTAINTED(ST(1));
+ this->priv_cert_is_tainted = SvTAINTED(ST(1));
+
+ SvREFCNT_inc(ST(0));
+ RETVAL = ST(0);
+ OUTPUT:
+ RETVAL
+
SV*
setPublicKey(Crypt_SMIME this, SV* crt)
CODE:
diff -ru Crypt-SMIME-0.16_original/lib/SMIME.pm Crypt-SMIME-0.16/lib/SMIME.pm
--- Crypt-SMIME-0.16_original/lib/SMIME.pm 2015-10-05 03:54:58.000000000 +0200
+++ Crypt-SMIME-0.16/lib/SMIME.pm 2016-06-21 00:05:45.721664200 +0200
@@ -273,6 +273,15 @@
if it fails to load the key.
+=item setPrivateKeyPkcs12()
+
+ $smime->setPrivateKeyPkcs12($key, $pkcs12);
+ $smime->setPrivateKeyPkcs12($key, $pkcs12, $password);
+
+Load a private key and its X.509 certificate from PKCS12 into the instance.
+The private key will be used for signing and decryption. The method dies if
+it fails to load PKCS12.
+
=item setPublicKey()
$smime->setPublicKey($crt);
diff -ru Crypt-SMIME-0.16_original/t/01-smime.t Crypt-SMIME-0.16/t/01-smime.t
--- Crypt-SMIME-0.16_original/t/01-smime.t 2014-05-07 07:46:12.000000000 +0200
+++ Crypt-SMIME-0.16/t/01-smime.t 2016-06-21 00:23:21.628075000 +0200
@@ -8,7 +8,7 @@
use Test::Exception;
use Config;
-my (%key, %csr, %crt);
+my (%key, %csr, %crt, %p12);
do {
my $OPENSSL = do {
if (defined(my $prefix = ExtUtils::PkgConfig->variable('openssl', 'prefix'))) {
@@ -49,10 +49,12 @@
(undef, $key{$i}) = tempfile(UNLINK => 1);
(undef, $csr{$i}) = tempfile(UNLINK => 1);
(undef, $crt{$i}) = tempfile(UNLINK => 1);
+ (undef, $p12{$i}) = tempfile(UNLINK => 1);
system(qq{$OPENSSL genrsa -out $key{$i} >$DEVNULL 2>&1}) and die $!;
system(qq{$OPENSSL req -new -key $key{$i} -out $csr{$i} -config $conf_file >$DEVNULL 2>&1}) and die $!;
system(qq{$OPENSSL x509 -in $csr{$i} -out $crt{$i} -req -signkey $key{$i} -set_serial $i >$DEVNULL 2>&1}) and die $!;
+ system(qq{$OPENSSL pkcs12 -export -out $p12{$i} -inkey $key{$i} -in $crt{$i} -passout pass:Secret123 >$DEVNULL 2>&1}) and die $!;
}
};
@@ -72,6 +74,15 @@
return scalar <$fh>;
}
+sub p12 {
+ my $i = shift;
+
+ local $/;
+ open my $fh, '<', $p12{$i} or die $!;
+ binmode $fh;
+ return scalar <$fh>;
+}
+
my $plain = q{From: alice@example.org
To: bob@example.org
Subject: Crypt::SMIME test
@@ -86,7 +97,7 @@
$verify =~ s/\r?\n|\r/\r\n/g;
#-----------------------
-plan tests => 24;
+plan tests => 25;
use_ok('Crypt::SMIME');
my $smime;
@@ -128,4 +139,7 @@
$smime->setPrivateKey(key(2), crt(2));
ok($decrypted = $smime->decrypt($encrypted), 'decrypt (by recipient\'s key)');
+$smime->setPrivateKeyPkcs12(p12(2), 'Secret123');
+ok($decrypted = $smime->decrypt($encrypted), 'decrypt (by recipient\'s PKCS12 key)');
+
1;