support public key extraction for libraries with non-compliant CKA_EC_POINT implementations - #65
Conversation
…C_POINT` implementations (with no OCTET STRING encapsulation)
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for extracting public keys from libraries that do not encapsulate the CKA_EC_POINT attribute within an OCTET STRING as specified by the standard. It introduces an alternate decoding path and prints a warning if the conventional decoding fails.
- Added alternate decoding logic for the CKA_EC_POINT attribute in multiple modules.
- Updated warning messages and corresponding error handling.
- Recorded the change in the CHANGELOG.
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| lib/pkcs11_more.c | Added alternate logic for EC point decoding with a warning message |
| lib/pkcs11_cert_common.c | Introduced alternate decoding with a warning message and error recovery |
| lib/pkcs11_cat.c | Implemented alternate EC point decoding and warning on decoding failure |
| CHANGELOG.md | Documented the new behavior regarding non-compliant CKA_EC_POINT implementations |
| fprintf(stderr, "Warning: CKA_EC_POINT format likely not compliant, trying alternate way to decode public key\n"); | ||
| /* d2i_TYPE() will NULLify the destination pointer in case of error (??!) */ | ||
| /* we need to reset the value */ | ||
| if( (ec_point_container=ASN1_OCTET_STRING_new()) == NULL ) { | ||
| P_ERR(); | ||
| goto key_ec_error; | ||
| } | ||
|
|
||
| if(ASN1_OCTET_STRING_set(ec_point_container, oecpoint->pValue, oecpoint->ulValueLen) == 0) { | ||
| P_ERR(); | ||
| goto key_ec_error; | ||
| } |
There was a problem hiding this comment.
[nitpick] Noticing that similar alternate decoding logic is repeated across multiple files; consider refactoring this logic into a shared helper function to improve maintainability.
| fprintf(stderr, "Warning: CKA_EC_POINT format likely not compliant, trying alternate way to decode public key\n"); | |
| /* d2i_TYPE() will NULLify the destination pointer in case of error (??!) */ | |
| /* we need to reset the value */ | |
| if( (ec_point_container=ASN1_OCTET_STRING_new()) == NULL ) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| } | |
| if(ASN1_OCTET_STRING_set(ec_point_container, oecpoint->pValue, oecpoint->ulValueLen) == 0) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| } | |
| ec_point_container = decode_asn1_octet_string(oecpoint->pValue, oecpoint->ulValueLen); | |
| if (ec_point_container == NULL) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| } |
| P_ERR(); | ||
| goto err; | ||
| /* P_ERR(); */ | ||
| fprintf(stderr, "Warning: CKA_EC_POINT format likely not compliant, trying alternate way to decode public key\n"); |
There was a problem hiding this comment.
[nitpick] The alternate decoding code here is duplicated in other modules; refactoring it into a common function could reduce redundancy and ease future maintenance.
| pp = oecpoint->pValue; /* copy the pointer */ | ||
| if(d2i_ASN1_OCTET_STRING(&ec_point_container, &pp, oecpoint->ulValueLen) == NULL ) { | ||
| P_ERR(); | ||
| goto key_ec_error; | ||
| fprintf(stderr, "Warning: CKA_EC_POINT format likely not compliant, trying alternate way to decode public key\n"); | ||
| /* d2i_TYPE() will NULLify the destination pointer in case of error (??!) */ | ||
| /* we need to reset the value */ | ||
| if( (ec_point_container=ASN1_OCTET_STRING_new()) == NULL ) { | ||
| P_ERR(); | ||
| goto key_ec_error; | ||
| } | ||
|
|
||
| if(ASN1_OCTET_STRING_set(ec_point_container, oecpoint->pValue, oecpoint->ulValueLen) == 0) { | ||
| P_ERR(); | ||
| goto key_ec_error; | ||
| } |
There was a problem hiding this comment.
[nitpick] Similar to the other files, this repeated decoding fallback logic might benefit from being refactored into a central helper function for better code reuse.
| pp = oecpoint->pValue; /* copy the pointer */ | |
| if(d2i_ASN1_OCTET_STRING(&ec_point_container, &pp, oecpoint->ulValueLen) == NULL ) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| fprintf(stderr, "Warning: CKA_EC_POINT format likely not compliant, trying alternate way to decode public key\n"); | |
| /* d2i_TYPE() will NULLify the destination pointer in case of error (??!) */ | |
| /* we need to reset the value */ | |
| if( (ec_point_container=ASN1_OCTET_STRING_new()) == NULL ) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| } | |
| if(ASN1_OCTET_STRING_set(ec_point_container, oecpoint->pValue, oecpoint->ulValueLen) == 0) { | |
| P_ERR(); | |
| goto key_ec_error; | |
| } | |
| ec_point_container = decode_CKA_EC_POINT(oecpoint->pValue, oecpoint->ulValueLen); | |
| if (ec_point_container == NULL) { | |
| goto key_ec_error; |
|
@keldonin any interest in abstracting into common code? Maybe something like this... Probably out of scope for this PR, but something to consider. |
| @@ -548,8 +548,19 @@ EVP_PKEY *pkcs11_SPKI_from_EC(pkcs11AttrList *attrlist ) | |||
| ptr = attr->pValue; /* copy the pointer, check OpenSSL d2i & i2d API doc for details */ | |||
|
|
|||
| if(d2i_ASN1_OCTET_STRING(&ec_point_container, &ptr, attr->ulValueLen) == NULL ) { | |||
There was a problem hiding this comment.
Same comment as in pkcs11_cat
| @@ -378,8 +378,18 @@ func_rc pkcs11_more_object_with_label(pkcs11Context *p11Context, char *label) | |||
| /* openssl pattern: &pp will be incremented beyond size of DER struct */ | |||
| pp = oecpoint->pValue; /* copy the pointer */ | |||
| if(d2i_ASN1_OCTET_STRING(&ec_point_container, &pp, oecpoint->ulValueLen) == NULL ) { | |||
There was a problem hiding this comment.
Same comment as in pkcs11_cat
|
I don't have anything additional to add other than what @covertmatthew has already mentioned. Once that feedback is addressed, I am good to go. Apologies for the delay! |
|
@keldonin @jake32321 I've removed the duplicative creation of Compiled and spot tested: |
|
@covertmatthew I checked on the problematic library, it seems to work: LGTM |
support public key extraction for libraries with non-compliant
CKA_EC_POINTimplementations (with no OCTET STRING encapsulation)There are PKCS#11 libraries that do not encapsulate
CKA_EC_POINTproperly.According to the spec, a EC public key is a point encapsulated inside an OCTET STRING. It means the resulting format is, for uncompressed representation, something like this:
04[LEN]04{X-coord in hex}{Y-coord in hex}Unfortunately, there are PKCS#11 libraries not following the spec, and not encapsulating properly within a OCTET STRING:
04{X-coord in hex}{Y-coord in hex}This patch is detecting this condition and tries another way to decode the public key.
This affects
p11cat,p11more,p11reqandp11mkcert.Note that if the
CKA_EC_POINTcan't be decoded, a warning is printed on stderr: