-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Patch and enable tests with AWS-LC #855
base: master
Are you sure you want to change the base?
Conversation
test/openssl/test_pkey_dh.rb
Outdated
@@ -28,7 +28,7 @@ def test_new_break_on_non_fips | |||
end | |||
|
|||
def test_new_break_on_fips | |||
omit_on_non_fips | |||
omit_on_non_fips or return aws_lc? # This behavior only applies to OpenSSL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is equivalent to if !omit_on_non_fips; return aws_lc? end
which doesn't really make sense. I think you want return if aws_lc?
(or return unless openssl?
) on a separate line.
I'm not entirely sure if this test is useful to have in ruby/openssl's tests at all. OpenSSL's fips provider skipping generation and returning a pre-defined group sounds like an implementation detail to me. @junaruga What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll do return unless openssl?
for now. Agreed that this is probably a new implementation detail specific to OpenSSL FIPS, most libcrypto's normally don't deviate from the original behavior.
test/openssl/test_ssl.rb
Outdated
assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) | ||
# OpenSSL and LibreSSL return V_ERR_SELF_SIGNED_CERT_IN_CHAIN as the error code. | ||
# AWS-LC returns V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY as the error code. | ||
assert_includes [OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY], ssl.verify_result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might be getting inconsistent results because the certificates are not conformant to RFC 5280. We should instead fix the certificates (@ca_cert
and @svr_cert
in utils.rb
) so that they include SKI/AKI extensions.
ca_exts = [
["basicConstraints","CA:TRUE",true],
["keyUsage","cRLSign,keyCertSign",true],
+ ["subjectKeyIdentifier","hash",false],
]
ee_exts = [
["keyUsage","keyEncipherment,digitalSignature",true],
+ ["authorityKeyIdentifier","issuer:always,keyid:always",false],
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave this a shot, but this doesn't resolve the issue :(. Unfortunately, I think this has more to do with the fact that AWS-LC's certificate verification logic has not been updated to align with later versions of OpenSSL. We plan to make this a better experience in the near future, but completing the work will take time. I'll also update the commit message to mention certificate verification logic differences to make things clearer.
I found a similar issue with LibreSSL in the same test that was fixed a while ago: a9954ba. The same assertion originally existed for LibreSSL, so I've changed the assertion to match the original format.
That being said, I can add the certificate improvements within the same commit if you'd like us to? Although it does seem different from the certificate verification logic issues this is trying to work around though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it seems like a different issue.
I think the actual cause might be that SSL_MODE_NO_AUTO_CHAIN
is turned on by default in AWS-LC, unlike OpenSSL: https://github.com/aws/aws-lc/blob/154f9986bc18f8f0e6126157a3abc84230456f77/include/openssl/ssl.h#L844-L861
ssl.peer_cert_chain
on the client SSLSocket
shows 2 certificates with OpenSSL and just 1 with AWS-LC, which explains the different error codes.
I don't think start_server
should depend on this behavior, and it doesn't seem intentional according to what I can see in git log in ruby/ruby's tree. I'll make a separate PR to fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#858 removed the cert store from start_server
which was triggering the different behavior.
test_verify_result
and test_connect_certificate_verify_failed_exception_message
should not need to relax the assertions.
test/openssl/test_pkcs7.rb
Outdated
# definite-length DER OCTET_STRING whereas upstream (i.e. | ||
# OpenSSL) encodes EncryptedContent as indefinite-length | ||
# BER OCTET_STRING. The discrepancy is due to AWS-LC's lack | ||
# of support for indefinite OCTET_STRINGS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this description is not accurate. The input (pki_msg.data
) uses indefinite length encodings, and OpenSSL re-encodes it into DER. AWS-LC's output is also DER, but the content is incorrect. If this is expected, I'd suggest skipping this test case for now.
Here is the inner PKCS#7 (pki_msg.data
), formatted to PEM:
-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHA6CAMIACAQAxggEQMIIBDAIBADB1MHAxEDAOBgNVBAoMB2V4
YW1wbGUxFzAVBgNVBAMMDlRBUk1BQyBST09UIENBMSIwIAYJKoZIhvcNAQkBFhNz
b21lb25lQGV4YW1wbGUub3JnMQswCQYDVQQGEwJVUzESMBAGA1UEBwwJVG93biBI
YWxsAgFmMA0GCSqGSIb3DQEBAQUABIGAbKV17HvGYRtRRBNz1QLpW763UedhVj5K
Xi70o4BJGM04lItAgt6aFC9SruZjpWr1gCYKCaRSAg273DeGTQwsDoZ86CPXzBpp
tYLz0MteQXYYWUaPZT+xmvx4NgDyk9P9MoT7JifsPrtXuzqCRFXhGdu8d/ru+OWx
hHLvKH+bYekwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgTbNlOZjLHf6CABIIC
EFOnLq/EAc9Nv+HjKR3ZVPSJMq0TImjGf5Mvc3nDgI572Hdo2aku0YXM6WjSWkpY
txpg7Cqxfl6hPSefLPUnBqlIoM2qbrE7MSKEVD6+2bW9GqYPFVg4qQLLsOxnxJIM
fOvLFfd7guL+iLH424XfiUUxaf8EdZE4u2IEl4REvkS1FoEGwyA4BEGMSeVPedQC
bZ0qY7Pc2tmZE3XfEUhIsyStG0Nb6i6AKcAFYGapbgE6kAB0gwsYcHlWMOvsvdAf
cTq6jwtHlO1s68qtvkWquTQ9lpX+fzddUUNxEHSqv5eU3oo6fT3Vj5ZFIVlaA5Th
ZMrI5PgRPuwJM4GL8/VLwY5mbDLFqn/irGeEvP99J3S87ornLLunjpxSy1/AymcV
ep2H32Tj82WS/IRQXBOzz4EnQRJGszKxAV6tY+Zje3sWyTTgObhlsiTQTDgnvtSW
8RvVHqKrwgkxxEsRHg7u8UdzZ0jg+O5+3F8B6/NWMyts0OaFqT9wvI8yO7VIy3dU
tGdz7Hde6Ggp/iTn1LbgdJ3N8Hzxf1j6NMWUKHVsadvwpRJbUeqq9c3+QuxsJi8w
WemxxQCE+tPyc1dP+ej5/M7bERbSOHMGgX03758IvP7A/fy2DjGPv2+lAwlEke0U
ze1367QKgxM0nc3SZDlptY7zPIJC5saWXb8Rt2bw2JxEBOTavrp+ZwJ8tcH961on
qwQIxOZ7YgJoLOQAAAAAAAAAAAAA
-----END PKCS7-----
Here is the EncryptedContentInfo
part in the der2ascii
output. It does show an indefinite length constructed encoding for EncryptedContent
(OCTET STRING), which is implicit tagged [0]
.
SEQUENCE indefinite {
# data
OBJECT_IDENTIFIER { 1.2.840.113549.1.7.1 }
SEQUENCE {
# DES-EDE3-CBC
OBJECT_IDENTIFIER { 1.2.840.113549.3.7 }
OCTET_STRING { `136cd94e6632c77f` }
}
[0] indefinite {
OCTET_STRING { `53a72[...snip]` }
OCTET_STRING { `c4e67b6202682ce4` }
}
}
In OpenSSL output (pki_message_content_pem
), EncryptedContent
uses an equivalent primitive encoding:
SEQUENCE {
# data
OBJECT_IDENTIFIER { 1.2.840.113549.1.7.1 }
SEQUENCE {
# DES-EDE3-CBC
OBJECT_IDENTIFIER { 1.2.840.113549.3.7 }
OCTET_STRING { `136cd94e6632c77f` }
}
[0 PRIMITIVE] { `53a72[...snip...]2ce4` }
}
In AWS-LC output (pki_message_content_pem_awslc
), EncryptedContent
also uses a primitive encoding, but the content contains extra OCTET STRING headers in it:
SEQUENCE {
# data
OBJECT_IDENTIFIER { 1.2.840.113549.1.7.1 }
SEQUENCE {
# DES-EDE3-CBC
OBJECT_IDENTIFIER { 1.2.840.113549.3.7 }
OCTET_STRING { `136cd94e6632c77f` }
}
[0 PRIMITIVE] {
OCTET_STRING { `53a72[...snip]` }
OCTET_STRING { `c4e67b6202682ce4` }
}
}
I took a look at AWS-LC's d2i_PKCS7()
and this part stood out to me: https://github.com/aws/aws-lc/blob/7518c784f4d6a8933345d9192b82ecc19bea4403/crypto/pkcs7/pkcs7_asn1.c#L45-L49
I haven't dug deeper yet, but CBS_asn1_ber_to_der()
not taking any contextual information seems odd, as correct conversion of structures like this would require it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great points and indeed there seems to be something we overlooked here. I'll sync up internally with our team to figure how to properly adjust this. Thanks!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done some deeper diving and I've pinned the reason down to AWS-LC's lack of support for ASN1_OCTET_STRING_NDEF
and the ASN1_TFLG_NDEF
flag. These act as a helper to request indefinite-length encoding for the ASN1 encoding functions in OpenSSL. This was removed from AWS-LC in this commit: aws/aws-lc@45858ae, and there's a mention of OpenSSL using this for their PKCS7 implementation within the commit message.
AWS-LC and OpenSSL both use the same generic ASN.1 functions which depend on the ASN.1 definition macros defined in each library. There's a slight difference in our definitions that I discovered here:
- https://github.com/aws/aws-lc/blob/154f9986bc18f8f0e6126157a3abc84230456f77/crypto/pkcs7/pkcs7_asn1.c#L149C5-L150
- https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/pkcs7/pk7_asn1.c#L148C51-L148C73
AWS-LC doesn't support the aforementioned ASN1_OCTET_STRING_NDEF
tag that OpenSSL uses for PKCS7 and we decided to explicitly tag the type as ASN1_OCTET_STRING
instead. This helps explain the additional OCTET STRING headers you're seeing with the translated ASN1 contents for AWS-LC.
I was looking through RFC2315's definition of EncryptedContentInfo
to double check and it does explicitly call out that the EncryptedContent
field should be an OCTET STRING
. It's also mentioned later on in section 10.3 that:
Definite-length encoding is more appropriate for simple types such as octet strings, so definite-length encoding is chosen.
Despite the slight difference, we think both OpenSSL and AWS-LC have valid ASN1 representations, just one has the explicit OCTET STRING header, while OpenSSL doesn't.
I really appreciate the help with this. I'll patch the test to be skipped with AWS-LC for the time being and document the actual root cause more accurately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Despite the slight difference, we think both OpenSSL and AWS-LC have valid ASN1 representations, just one has the explicit OCTET STRING header, while OpenSSL doesn't.
I'm afraid you are mixing something up here. Both outputs are well formed DER (then formatted to PEM), but they are representations of different data. The contents octets of EncryptedContent
in AWS-LC's start with 04 82 02 10 53 a7 ...
instead of the correct 53 a7 ...
.
Ideally AWS-LC should either produce the identical output as OpenSSL, since DER is deterministic, or make d2i_PKCS7{,_bio}()
return an error if such an input is not supported.
Anyway, skipping it in ruby/openssl's test suite seems reasonable for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverting aws/aws-lc@2a72226 makes d2i_PKCS7{,_bio}()
report an error when it encounters the constructed encoding of octet string (EncryptedContent
).
I think reintroducing support for parsing constructed encoding of strings might require reverting this commit (perhaps excluding the part related to indefinite lengths): aws/aws-lc@a70edd4
AWS-LC's FIPS mode is decided at compile time. FIPS in AWS-LC can't be toggled on and off like OpenSSL, so tests that attempt to do so are incompatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks the review! We're still discussing a path forward on the PKCS7 comment/issue, but I've attempted to address the rest of your comments.
test/openssl/test_pkey_dh.rb
Outdated
@@ -28,7 +28,7 @@ def test_new_break_on_non_fips | |||
end | |||
|
|||
def test_new_break_on_fips | |||
omit_on_non_fips | |||
omit_on_non_fips or return aws_lc? # This behavior only applies to OpenSSL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll do return unless openssl?
for now. Agreed that this is probably a new implementation detail specific to OpenSSL FIPS, most libcrypto's normally don't deviate from the original behavior.
test/openssl/test_ssl.rb
Outdated
assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, ssl.verify_result) | ||
# OpenSSL and LibreSSL return V_ERR_SELF_SIGNED_CERT_IN_CHAIN as the error code. | ||
# AWS-LC returns V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY as the error code. | ||
assert_includes [OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY], ssl.verify_result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave this a shot, but this doesn't resolve the issue :(. Unfortunately, I think this has more to do with the fact that AWS-LC's certificate verification logic has not been updated to align with later versions of OpenSSL. We plan to make this a better experience in the near future, but completing the work will take time. I'll also update the commit message to mention certificate verification logic differences to make things clearer.
I found a similar issue with LibreSSL in the same test that was fixed a while ago: a9954ba. The same assertion originally existed for LibreSSL, so I've changed the assertion to match the original format.
That being said, I can add the certificate improvements within the same commit if you'd like us to? Although it does seem different from the certificate verification logic issues this is trying to work around though.
test/openssl/test_pkcs7.rb
Outdated
# definite-length DER OCTET_STRING whereas upstream (i.e. | ||
# OpenSSL) encodes EncryptedContent as indefinite-length | ||
# BER OCTET_STRING. The discrepancy is due to AWS-LC's lack | ||
# of support for indefinite OCTET_STRINGS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great points and indeed there seems to be something we overlooked here. I'll sync up internally with our team to figure how to properly adjust this. Thanks!!
1fdf97d
to
637b6c6
Compare
AWS-LC does not support the KEY_SIG or KEY_EX flags that were only ever supported by old MSIE.
AWS-LC does not support BN_FLG_CONSTTIME due to its historically inconsistent constant-time guarantees.
AWS-LC has a few minor functionalities removed from NCONF_get_string. 1. Expanding of $foo to a previously-parsed value was removed. 2. OpenSSL falls back to using "default" with an unknown "section". AWS-LC does not support this behavior. 3. AWS-LC does not support parsing environment variables with "ENV" like LibreSSL.
AWS-LC's ASN1 parsing capabilities led to us examine some of our ASN1 tests. One test in test_asn1.rb happens to use a tag number of 8224. There are concerns with larger UNIVERSAL tags being ambiguous with negative ASN1 Integers, so I've adjusted the test to use CONTEXT_SPECIFIC instead with the same tag number (8224).
1. AWS-LC has no support for SMIME with PKCS7. That may change in the near future, so I've marked that with "pend" for now. 2. AWS-LC doesn't support printing of PKCS7 contents with PKCS7_print_ctx. 3. OpenSSL traditionally used indefinite-length encoding with ASN1_TFLG_NDEF in its implementation for PKCS7 EncryptedContent. AWS-LC uses explicit OCTET STRING headers to encode instead, which leads to a slight difference in serialized ASN1 contents from the two libraries.
OpenSSL allows invalid EC keys or DH params to be parsed. The consuming application can then run parameter/key checks to check the validity of the parameters. We happen to run tests to verify that this behaves as expected. AWS-LC on the other hand, directly raises an error and disallows the invalid state to be parsed, rather than making it parsable and checking the validity later. Relevant tests have been adjusted accordingly to reflect this.
EVP_DigestVerify in OpenSSL returns 0 to indicate a signature verification failure and can return -1 to indicate other failures, such as invalid ASN1 contents. ruby/openssl also reflects that by returning false with 0 and raising an error with -1. EVP_DigestVerify in AWS-LC simply returns 0 for any failure.
We reecently tweaked some break tests in test_pkey_dh.rb due to different behavior with OpenSSL in FIPS mode. AWS-LC does not inherit the same specific behavior, so tests have been adjusted accordingly.
637b6c6
to
c4d77bf
Compare
There are a few SSL discrepencies in AWS-LC when compared to OpenSSL. 1. AWS-LC has slightly different error messages (in all-caps). 2. AWS-LC has no support for DHE ciphersuites. 3. There are no concepts of SSL security levels within AWS-LC. 4. Similar to LibreSSL, there is no support for OPENSSL_CONF. 5. AWS-LC emits slightly different certificate verification logic errors compared to current versions of OpenSSL.
The SSL SESSION files we were originally testing against use DHE and SSLv3. AWS-LC happens to have no support for either and we have newer possible alternatives available, so I've updated the respective files to use ECDHE-RSA-AES256-SHA with TLS 1.1 and 1.2. I've verified that these work as expected with all libcryptos we support. There are also a few SSL session discrepencies in AWS-LC when compared to OpenSSL. 1. AWS-LC has no support for internal session caching on the client-end. 2. AWS-LC supports internal session caching on the server, but SSL_get1_session does not return a resumable session with TLS 1.3 in AWS-LC. Users have to use the SSL_CTX_sess_set_new_cb (ctx.session_new_cb in Ruby) to retrieve the resumable session ticket. 3. AWS-LC has no current support for external session caching in TLS 1.3.
c4d77bf
to
d8bc0cb
Compare
def assert_sign_verify_false_or_error | ||
begin | ||
assert_equal(false, yield) | ||
rescue => e | ||
assert_kind_of(OpenSSL::PKey::PKeyError, e) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my earlier suggestion wasn't right as the rescue
clause would incorrectly catch an assertion failure from assert_equal
(which utilizes exceptions). I think something like this should work:
def assert_sign_verify_false_or_error | |
begin | |
assert_equal(false, yield) | |
rescue => e | |
assert_kind_of(OpenSSL::PKey::PKeyError, e) | |
end | |
end | |
def assert_sign_verify_false_or_error | |
ret = yield | |
rescue => e | |
assert_kind_of(OpenSSL::PKey::PKeyError, e) | |
else | |
assert_equal(false, ret) | |
end |
Second follow up from #833
This contribution should be the next and final phase for adding support for AWS-LC in the ruby/openssl gem. These changes represent the build portion of a larger patch in the AWS-LC's Ruby integration CI. With this change, all tests have been accounted for and reenabled in the CI.
I understand that this patch is a bit large, so I've broken everything up to into smaller documented commits that'll make things easier to digest. I've also tried following a similar commit messaging pattern that the maintainers use.
However, do feel free to let me know if I should make separate PR contributions for some of these or if there are any changes within the commit messages that I should adjust. Thank you!!