Skip to content

Commit 2ad0e14

Browse files
committed
Fix MGF support
Requires CryptX >= 0.081 which include the require rsa-oaep support for MGF
1 parent 0d24262 commit 2ad0e14

File tree

6 files changed

+244
-40
lines changed

6 files changed

+244
-40
lines changed

Makefile.PL

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ my %WriteMakefileArgs = (
2020
"Crypt::AuthEnc::GCM" => "0.062",
2121
"Crypt::Mode::CBC" => 0,
2222
"Crypt::OpenSSL::X509" => 0,
23-
"Crypt::PK::RSA" => 0,
23+
"Crypt::PK::RSA" => "0.081",
2424
"Crypt::PRNG" => 0,
2525
"MIME::Base64" => 0,
2626
"XML::LibXML" => 0,
@@ -31,6 +31,7 @@ my %WriteMakefileArgs = (
3131
},
3232
"TEST_REQUIRES" => {
3333
"Crypt::OpenSSL::Guess" => 0,
34+
"CryptX" => 0,
3435
"Exporter" => 0,
3536
"File::Slurper" => 0,
3637
"File::Which" => 0,
@@ -53,8 +54,9 @@ my %FallbackPrereqs = (
5354
"Crypt::Mode::CBC" => 0,
5455
"Crypt::OpenSSL::Guess" => 0,
5556
"Crypt::OpenSSL::X509" => 0,
56-
"Crypt::PK::RSA" => 0,
57+
"Crypt::PK::RSA" => "0.081",
5758
"Crypt::PRNG" => 0,
59+
"CryptX" => 0,
5860
"Exporter" => 0,
5961
"File::Slurper" => 0,
6062
"File::Which" => 0,

README

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,37 @@ METHODS
103103

104104
* mgf1sha512 <http://www.w3.org/2009/xmlenc11#mgf1sha512>
105105

106+
oaep_params
107+
Specify the OAEPparams value to use as part of the mask generation
108+
function (MGF). It is optional but can be specified for rsa-oaep and
109+
rsa-oaep-mgf1p EncryptionMethods.
110+
111+
It is base64 encoded and stored in the XML as OAEPparams.
112+
113+
If specified you MAY specify the oaep_label_hash that should be
114+
used. You should note that not all implementations support an
115+
oaep_label_hash that differs from that of the MGF specified in the
116+
xenc11:MGF element or the default MGF1 with SHA1.
117+
118+
The oaep_label_hash is stored in the DigestMethod child element of
119+
the EncryptionMethod.
120+
121+
oaep_label_hash
122+
Specify the Hash Algorithm to use for the rsa-oaep label as
123+
specified by oaep_params.
124+
125+
The default is sha1. Supported algorithms are:
126+
127+
* sha1 <http://www.w3.org/2000/09/xmldsig#sha1>
128+
129+
* sha224 <http://www.w3.org/2001/04/xmldsig-more#sha224>
130+
131+
* sha256 <http://www.w3.org/2001/04/xmlenc#sha256>
132+
133+
* sha384 <http://www.w3.org/2001/04/xmldsig-more#sha384>
134+
135+
* sha512 <http://www.w3.org/2001/04/xmlenc#sha512>
136+
106137
decrypt( ... )
107138
Main decryption function.
108139

@@ -121,7 +152,7 @@ AUTHOR
121152
Timothy Legge <[email protected]>
122153

123154
COPYRIGHT AND LICENSE
124-
This software is copyright (c) 2023 by TImothy Legge.
155+
This software is copyright (c) 2024 by TImothy Legge.
125156

126157
This is free software; you can redistribute it and/or modify it under
127158
the same terms as the Perl 5 programming language system itself.

cpanfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ requires "Carp" => "0";
44
requires "Crypt::AuthEnc::GCM" => "0.062";
55
requires "Crypt::Mode::CBC" => "0";
66
requires "Crypt::OpenSSL::X509" => "0";
7-
requires "Crypt::PK::RSA" => "0";
7+
requires "Crypt::PK::RSA" => "0.081";
88
requires "Crypt::PRNG" => "0";
99
requires "MIME::Base64" => "0";
1010
requires "XML::LibXML" => "0";
@@ -16,6 +16,7 @@ requires "warnings" => "0";
1616

1717
on 'test' => sub {
1818
requires "Crypt::OpenSSL::Guess" => "0";
19+
requires "CryptX" => "0";
1920
requires "Exporter" => "0";
2021
requires "File::Slurper" => "0";
2122
requires "File::Which" => "0";

lib/XML/Enc.pm

Lines changed: 136 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package XML::Enc;
99
use Carp;
1010
use Crypt::AuthEnc::GCM 0.062;
1111
use Crypt::Mode::CBC;
12-
use Crypt::PK::RSA;
12+
use Crypt::PK::RSA 0.081;
1313
use Crypt::PRNG qw( random_bytes );
1414
use MIME::Base64 qw/decode_base64 encode_base64/;
1515
use XML::LibXML;
@@ -107,8 +107,10 @@ sub _assert_encryption_digest {
107107
state $ENC_DIGEST = {
108108
'http://www.w3.org/2000/09/xmldsig#sha1' => 'SHA1',
109109
'http://www.w3.org/2001/04/xmlenc#sha256' => 'SHA256',
110+
'http://www.w3.org/2001/04/xmldsig-more#sha224' => 'SHA224',
111+
'http://www.w3.org/2001/04/xmldsig-more#sha384' => 'SHA384',
112+
'http://www.w3.org/2001/04/xmlenc#sha512' => 'SHA512',
110113
};
111-
112114
die "Unsupported encryption digest algo $algo" unless $ENC_DIGEST->{ $algo };
113115
return $ENC_DIGEST->{ $algo };
114116
}
@@ -196,6 +198,37 @@ Used in encryption. Optional. Default method: mgf1sha1
196198
197199
=back
198200
201+
=item B<oaep_params>
202+
203+
Specify the OAEPparams value to use as part of the mask generation function (MGF).
204+
It is optional but can be specified for rsa-oaep and rsa-oaep-mgf1p EncryptionMethods.
205+
206+
It is base64 encoded and stored in the XML as OAEPparams.
207+
208+
If specified you MAY specify the oaep_label_hash that should be used. You should note
209+
that not all implementations support an oaep_label_hash that differs from that of the
210+
MGF specified in the xenc11:MGF element or the default MGF1 with SHA1.
211+
212+
The oaep_label_hash is stored in the DigestMethod child element of the EncryptionMethod.
213+
214+
=item B<oaep_label_hash>
215+
216+
Specify the Hash Algorithm to use for the rsa-oaep label as specified by oaep_params.
217+
218+
The default is sha1. Supported algorithms are:
219+
220+
=over
221+
222+
=item * L<sha1|http://www.w3.org/2000/09/xmldsig#sha1>
223+
224+
=item * L<sha224|http://www.w3.org/2001/04/xmldsig-more#sha224>
225+
226+
=item * L<sha256|http://www.w3.org/2001/04/xmlenc#sha256>
227+
228+
=item * L<sha384|http://www.w3.org/2001/04/xmldsig-more#sha384>
229+
230+
=item * L<sha512|http://www.w3.org/2001/04/xmlenc#sha512>
231+
199232
=back
200233
201234
=cut
@@ -225,8 +258,12 @@ sub new {
225258
my $key_method = exists($params->{'key_transport'}) ? $params->{'key_transport'} : 'rsa-oaep-mgf1p ';
226259
$self->{'key_transport'} = $self->_setKeyEncryptionMethod($key_method);
227260

228-
my $oaep_mgf_alg = exists($params->{'oaep_mgf_alg'}) ? $params->{'oaep_mgf_alg'} : 'http://www.w3.org/2009/xmlenc11#mgf1sha1';
229-
$self->{'oaep_mgf_alg'} = $self->_setOAEPAlgorithm($oaep_mgf_alg);
261+
if (exists $params->{'oaep_mgf_alg'}) {
262+
$self->{'oaep_mgf_alg'} = $self->_setOAEPAlgorithm($params->{'oaep_mgf_alg'});
263+
}
264+
if (exists $params->{'oaep_label_hash'} ) {
265+
$self->{'oaep_label_hash'} = $self->_setOAEPDigest($params->{'oaep_label_hash'});
266+
}
230267

231268
$self->{'oaep_params'} = exists($params->{'oaep_params'}) ? $params->{'oaep_params'} : '';
232269

@@ -576,6 +613,36 @@ sub _getOAEPAlgorithm {
576613
return $OAEPAlgorithm->{$method} // 'SHA1';
577614
}
578615

616+
sub _setOAEPDigest {
617+
my $self = shift;
618+
my $method = shift;
619+
620+
state $OAEPDigest = {
621+
'sha1' => 'http://www.w3.org/2000/09/xmldsig#sha1',
622+
'sha224' => 'http://www.w3.org/2001/04/xmldsig-more#sha224',
623+
'sha256' => 'http://www.w3.org/2001/04/xmlenc#sha256',
624+
'sha384' => 'http://www.w3.org/2001/04/xmldsig-more#sha384',
625+
'sha512' => 'http://www.w3.org/2001/04/xmlenc#sha512',
626+
};
627+
628+
return $OAEPDigest->{$method} // $OAEPDigest->{'sha256'};
629+
}
630+
631+
sub _getParamsAlgorithm {
632+
my $self = shift;
633+
my $method = shift;
634+
635+
state $ParamsAlgorithm = {
636+
'http://www.w3.org/2000/09/xmldsig#sha1' => 'SHA1',
637+
'http://www.w3.org/2001/04/xmldsig-more#sha224' => 'SHA224',
638+
'http://www.w3.org/2001/04/xmlenc#sha256' => 'SHA256',
639+
'http://www.w3.org/2001/04/xmldsig-more#sha384' => 'SHA384',
640+
'http://www.w3.org/2001/04/xmlenc#sha512' => 'SHA512',
641+
};
642+
643+
return $ParamsAlgorithm->{$method} // $ParamsAlgorithm->{'http://www.w3.org/2000/09/xmldsig#sha1'};
644+
}
645+
579646
sub _setKeyEncryptionMethod {
580647
my $self = shift;
581648
my $method = shift;
@@ -681,23 +748,45 @@ sub _decrypt_key {
681748
if ($algo eq 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p') {
682749
return _decrypt(
683750
sub {
684-
$self->{key_obj}->decrypt(
685-
$key, 'oaep',
686-
$digest_name // 'SHA1',
687-
$oaep // ''
688-
);
751+
if ($CryptX::VERSION le 0.081) {
752+
#print "Caller: _decrypt_key rsa-oaep-mgf1p\n";
753+
$self->{key_obj}->decrypt(
754+
$key, 'oaep',
755+
#$self->_getOAEPAlgorithm($mgf),
756+
$digest_name // 'SHA1',
757+
$oaep // '',
758+
);
759+
} else {
760+
#print "Caller: _decrypt_key rsa-oaep-mgf1p\n";
761+
#print "digest_name: ", $digest_name, "\n";
762+
$self->{key_obj}->decrypt(
763+
$key, 'oaep',
764+
$mgf // 'SHA1',
765+
$oaep // '',
766+
$digest_name // 'SHA1',
767+
);
768+
}
689769
}
690770
);
691771
}
692772

693773
if ($algo eq 'http://www.w3.org/2009/xmlenc11#rsa-oaep') {
694774
return _decrypt(
695775
sub {
696-
$self->{key_obj}->decrypt(
697-
$key, 'oaep',
698-
$self->_getOAEPAlgorithm($mgf),
699-
$oaep // '',
700-
);
776+
if ($CryptX::VERSION le 0.081) {
777+
$self->{key_obj}->decrypt(
778+
$key, 'oaep',
779+
$self->_getOAEPAlgorithm($mgf),
780+
$oaep // '',
781+
);
782+
} else {
783+
$self->{key_obj}->decrypt(
784+
$key, 'oaep',
785+
$self->_getOAEPAlgorithm($mgf),
786+
$oaep // '',
787+
$digest_name // '',
788+
);
789+
}
701790
}
702791
);
703792
}
@@ -712,14 +801,29 @@ sub _EncryptKey {
712801

713802
my $rsa_pub = $self->{cert_obj};
714803

804+
# FIXME: this could use some refactoring and some simplfication
715805
if ($keymethod eq 'http://www.w3.org/2001/04/xmlenc#rsa-1_5') {
716806
${$key} = $rsa_pub->encrypt(${$key}, 'v1.5');
717807
}
718808
elsif ($keymethod eq 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p') {
719-
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', 'SHA1', $self->{oaep_params});
809+
if ($CryptX::VERSION le 0.081) {
810+
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', 'SHA1', $self->{oaep_params});
811+
} else {
812+
my $oaep_label_hash = (defined $self->{oaep_label_hash} && $self->{oaep_label_hash} ne '') ?
813+
$self->_getParamsAlgorithm($self->{oaep_label_hash}) : 'SHA1';
814+
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', 'SHA1', $self->{oaep_params}, $oaep_label_hash);
815+
}
720816
}
721817
elsif ($keymethod eq 'http://www.w3.org/2009/xmlenc11#rsa-oaep') {
722-
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', $self->_getOAEPAlgorithm($self->{oaep_mgf_alg}), $self->{oaep_params});
818+
my $mgf_hash = defined $self->{oaep_mgf_alg} ?
819+
$self->_getOAEPAlgorithm($self->{oaep_mgf_alg}) : undef;
820+
if ($CryptX::VERSION le 0.081) {
821+
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', $mgf_hash, $self->{oaep_params});
822+
} else {
823+
my $oaep_label_hash = (defined $self->{oaep_label_hash} && $self->{oaep_label_hash} ne '') ?
824+
$self->_getParamsAlgorithm($self->{oaep_label_hash}) : $mgf_hash;
825+
${$key} = $rsa_pub->encrypt(${$key}, 'oaep', $mgf_hash, $self->{oaep_params}, $oaep_label_hash);
826+
}
723827
} else {
724828
die "Unsupported algorithm for key encyption $keymethod}";
725829
}
@@ -1030,6 +1134,20 @@ sub _create_encrypted_data_xml {
10301134
}
10311135
);
10321136

1137+
if ($self->{key_transport} eq 'http://www.w3.org/2009/xmlenc11#rsa-oaep' ||
1138+
$self->{key_transport} eq 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' &&
1139+
$self->{oaep_label_hash}) {
1140+
my $digestmethod = $self->_create_node(
1141+
$doc,
1142+
$dsigns,
1143+
$kencmethod,
1144+
'dsig:DigestMethod',
1145+
{
1146+
Algorithm => $self->{oaep_label_hash},
1147+
}
1148+
);
1149+
};
1150+
10331151
if ($self->{'oaep_params'} ne '') {
10341152
my $oaep_params = $self->_create_node(
10351153
$doc,
@@ -1039,7 +1157,8 @@ sub _create_encrypted_data_xml {
10391157
);
10401158
};
10411159

1042-
if ($self->{key_transport} eq 'http://www.w3.org/2009/xmlenc11#rsa-oaep') {
1160+
if ($self->{key_transport} eq 'http://www.w3.org/2009/xmlenc11#rsa-oaep' &&
1161+
$self->{oaep_mgf_alg}) {
10431162
my $oaepmethod = $self->_create_node(
10441163
$doc,
10451164
$xenc11ns,

0 commit comments

Comments
 (0)