@@ -2,8 +2,11 @@ use strict;
22use Test::More;
33
44use Crypt::OpenSSL::RSA;
5+ use Crypt::OpenSSL::Guess qw( openssl_version) ;
56
6- BEGIN { plan tests => 39 }
7+ my ($major , $minor , $patch ) = openssl_version();
8+
9+ BEGIN { plan tests => 48 }
710
811my $PRIVATE_KEY_STRING = <<EOF ;
912-----BEGIN RSA PRIVATE KEY-----
@@ -148,6 +151,50 @@ like($@, qr/unrecognized key format/, "new_public_key croaks on certificate PEM
148151eval { Crypt::OpenSSL::RSA-> new_public_key(" not a PEM key at all" ) };
149152like($@ , qr / unrecognized key format/ , " new_public_key croaks on non-PEM input" );
150153
154+ # --- PKCS#8 private key export ---
155+
156+ {
157+ my $rsa = Crypt::OpenSSL::RSA-> new_private_key($DECRYPT_PRIVATE_KEY_STRING );
158+ my $pkcs8_pem = $rsa -> get_private_key_pkcs8_string();
159+ like($pkcs8_pem , qr / ^-----BEGIN PRIVATE KEY-----/ m , " PKCS#8 output has correct header" );
160+ like($pkcs8_pem , qr / -----END PRIVATE KEY-----\s *$ / m , " PKCS#8 output has correct footer" );
161+ unlike($pkcs8_pem , qr / BEGIN RSA PRIVATE KEY/ , " PKCS#8 output is not PKCS#1 format" );
162+
163+ # encrypted PKCS#8 export
164+ my $pass = ' test_pkcs8_pass' ;
165+ my $enc_pem = $rsa -> get_private_key_pkcs8_string($pass , ' aes-128-cbc' );
166+ like($enc_pem , qr / ^-----BEGIN ENCRYPTED PRIVATE KEY-----/ m ,
167+ " encrypted PKCS#8 has correct header" );
168+
169+ # Round-trip tests require new_private_key to read PKCS#8. On pre-3.x
170+ # PEM_read_bio_PrivateKey is macro'd to PEM_read_bio_RSAPrivateKey which
171+ # only reads PKCS#1, so these must be skipped.
172+ SKIP: {
173+ skip " new_private_key cannot read PKCS#8 on OpenSSL < 3.x" , 3
174+ if $major < 3;
175+
176+ my $reimported = Crypt::OpenSSL::RSA-> new_private_key($pkcs8_pem );
177+ is($reimported -> get_private_key_string(), $DECRYPT_PRIVATE_KEY_STRING ,
178+ " PKCS#8 round-trip: re-import then export as PKCS#1 matches original" );
179+ is($reimported -> get_private_key_pkcs8_string(), $pkcs8_pem ,
180+ " PKCS#8 round-trip: re-export as PKCS#8 matches" );
181+
182+ my $dec_rsa = Crypt::OpenSSL::RSA-> new_private_key($enc_pem , $pass );
183+ is($dec_rsa -> get_private_key_string(), $DECRYPT_PRIVATE_KEY_STRING ,
184+ " encrypted PKCS#8 round-trip decrypts to original key" );
185+ }
186+
187+ # error: cipher without passphrase
188+ eval { $rsa -> get_private_key_pkcs8_string(undef , ' des3' ) };
189+ like($@ , qr / Passphrase is required for cipher/ ,
190+ " get_private_key_pkcs8_string croaks when cipher given without passphrase" );
191+
192+ # error: unsupported cipher
193+ eval { $rsa -> get_private_key_pkcs8_string($pass , ' bogus-cipher-xyz' ) };
194+ like($@ , qr / Unsupported cipher/ ,
195+ " get_private_key_pkcs8_string croaks on unsupported cipher" );
196+ }
197+
151198# --- X509 public key from private key matches PKCS1 ---
152199
153200my $priv_for_x509 = Crypt::OpenSSL::RSA-> new_private_key($PRIVATE_KEY_STRING );
0 commit comments