cryptopp-pem
cryptopp-pem copied to clipboard
BERDecodeSubjectPublicKeyInfo failed to read an EC public key that explicitly contains EC parameters from a certificate
When I use the following code to read an EC public key from a certificate that explicitly contains the EC parameters, the program fails to work as expected:
#include "cryptlib.h"
#include "x509cert.h"
#include "filters.h"
#include "sha.h"
#include "hex.h"
#include "pem.h"
#include "files.h"
#include <iostream>
#include <string>
extern const std::string pemCertificate;
int main(int argc, char* argv[])
{
using namespace CryptoPP;
StringSource ss(pemCertificate, true);
X509Certificate cert;
PEM_Load(ss, cert);
const X509PublicKey& publicKey = cert.GetSubjectPublicKey(); // fail
}
const std::string pemCertificate =
"-----BEGIN CERTIFICATE-----\r\n"
"MIICcjCCAhegAwIBAgIUC8OM0gRX41iXU2vLJbGmRjDMzTMwCgYIKoZIzj0EAwIw\r\n"
"FDESMBAGA1UEAwwJTUFMRk9STUVEMB4XDTI0MDIyNzA1MTU0NVoXDTI1MDIyMTA1\r\n"
"MTU0NVowFDESMBAGA1UEAwwJTUFMRk9STUVEMIIBSzCCAQMGByqGSM49AgEwgfcC\r\n"
"AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\r\n"
"MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\r\n"
"vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\r\n"
"axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\r\n"
"K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\r\n"
"YyVRAgEBA0IABL/gnM66tzV2I+W/+nnMwDP0XT/HHyQlE3CXNm+JTRHKNRMyJRX6\r\n"
"Y5y5RIPdXfsfja9XJt4gjYuazSo8uAqkbRqjUzBRMB0GA1UdDgQWBBRZfvu1C6ya\r\n"
"pgoCyrWwx+fyQ95PJzAfBgNVHSMEGDAWgBRZfvu1C6yapgoCyrWwx+fyQ95PJzAP\r\n"
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCN9TitNg9mjUHSIQ9k\r\n"
"qieJjJtgkaOLA1f/h8Bs/sKNTQIhAMLhp4UgPphR1XhkLd9WN4oclaJ1M/ceLcKV\r\n"
"6pcPVk1J\r\n"
"-----END CERTIFICATE-----\r\n";
At first, I thought that the code for handling public keys that explicitly contains the EC parameters wasn't implemented in cryptopp-pem. However, later I realized that it seems to be implemented, but there are some issues with the implementation.
The issue lies in the line 1231 in function GetSubjectPublicKeyInfoOids, due to the inconsistency in the structure between EC public key that explicitly contain EC parameters and normal EC public key, the GetSubjectPublicKeyInfoOids function incorrectly parse the value of field as NULL after execution.
The reason for incorrectly parsing field to NULL lies in the GetSubjectPublicKeyInfoOids function, which expects to set algorithm and field to their corresponding OIDs through two separate decode operations in line 1279 and line 1282. This is because, in a normal public key as shown below, algorithm and field occur consecutively, allowing them to be properly set as their corresponding OIDs through this method:
123 86: SEQUENCE {
125 16: SEQUENCE {
127 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) // algorithm
136 5: OBJECT IDENTIFIER secp256k1 (1 3 132 0 10) // field
: }
143 66: BIT STRING
: 04 76 1F D6 09 08 4B 41 1D 99 83 1F 38 6E DB 9A
: 4A FB 7F 94 1A 0F CE 79 16 93 F3 B9 BD BB 8F 3E
: FE 4A F2 FE 1C B0 9B 93 5E 37 FE 5E 14 47 84 2E
: 28 E8 B7 49 F4 52 5E 53 B7 F0 C3 0F D9 CC DF 03
: 57
: }
When an EC public key explicitly contains parameters, its public key structure becomes as follows:
127 259: SEQUENCE {
131 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) // algorithm
140 247: SEQUENCE {
143 1: INTEGER 1
146 44: SEQUENCE {
148 7: OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1) // field
157 33: INTEGER
: 00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
: 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
: FF
: }
...
It can be seen that, in this case, what directly follows the algorithm is no longer an OID but a SEQUENCE, and field resides within this SEQUENCE. Therefore, when attempting to set algorithm and field as their corresponding OIDs through two consecutive decode operations, the program incorrectly decodes the SEQUENCE as an OID. Clearly, this results in decoding failure, leading to the setting of field as NULL.
Once field is set to NULL, this leads to subsequent functions in BERDecodeSubjectPublicKeyInfo such as IsECPrimeFieldAlgorithm or IsECBinaryFieldAlgorithm, erroneously considering that the public key does not belong to an EC public key, thus terminating and reporting an error.
fix
Thanks @roadicing,
Out of curiosity, where did the certificate come from?
If the certificate(s) are publicly available, then I would like to get some test cases setup, like https://github.com/noloader/cryptopp-pem/blob/master/pem_test.cxx#L379 and https://github.com/noloader/cryptopp-pem/blob/master/pem_test.cxx#L444.
The certificate piqued my curiosity:
$ openssl x509 -in test-cert.pem -inform PEM -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0b:c3:8c:d2:04:57:e3:58:97:53:6b:cb:25:b1:a6:46:30:cc:cd:33
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN = MALFORMED
Validity
Not Before: Feb 27 05:15:45 2024 GMT
Not After : Feb 21 05:15:45 2025 GMT
Subject: CN = MALFORMED
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:bf:e0:9c:ce:ba:b7:35:76:23:e5:bf:fa:79:cc:
c0:33:f4:5d:3f:c7:1f:24:25:13:70:97:36:6f:89:
4d:11:ca:35:13:32:25:15:fa:63:9c:b9:44:83:dd:
5d:fb:1f:8d:af:57:26:de:20:8d:8b:9a:cd:2a:3c:
b8:0a:a4:6d:1a
Field Type: prime-field
Prime:
00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:ff
A:
00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:fc
B:
5a:c6:35:d8:aa:3a:93:e7:b3:eb:bd:55:76:98:86:
bc:65:1d:06:b0:cc:53:b0:f6:3b:ce:3c:3e:27:d2:
60:4b
Generator (uncompressed):
04:6b:17:d1:f2:e1:2c:42:47:f8:bc:e6:e5:63:a4:
40:f2:77:03:7d:81:2d:eb:33:a0:f4:a1:39:45:d8:
98:c2:96:4f:e3:42:e2:fe:1a:7f:9b:8e:e7:eb:4a:
7c:0f:9e:16:2b:ce:33:57:6b:31:5e:ce:cb:b6:40:
68:37:bf:51:f5
Order:
00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff:
ff:ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc:
63:25:51
Cofactor: 1 (0x1)
Seed:
c4:9d:36:08:86:e7:04:93:6a:66:78:e1:13:9d:26:
b7:81:9f:7e:90
X509v3 extensions:
X509v3 Subject Key Identifier:
59:7E:FB:B5:0B:AC:9A:A6:0A:02:CA:B5:B0:C7:E7:F2:43:DE:4F:27
X509v3 Authority Key Identifier:
59:7E:FB:B5:0B:AC:9A:A6:0A:02:CA:B5:B0:C7:E7:F2:43:DE:4F:27
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:46:02:21:00:8d:f5:38:ad:36:0f:66:8d:41:d2:21:0f:64:
aa:27:89:8c:9b:60:91:a3:8b:03:57:ff:87:c0:6c:fe:c2:8d:
4d:02:21:00:c2:e1:a7:85:20:3e:98:51:d5:78:64:2d:df:56:
37:8a:1c:95:a2:75:33:f7:1e:2d:c2:95:ea:97:0f:56:4d:49
And:
$ openssl x509 -in test-cert.pem -inform PEM -outform DER | dumpasn1 -
Warning: Input is non-seekable, some functionality has been disabled.
0 626: SEQUENCE {
4 535: SEQUENCE {
8 3: [0] {
10 1: INTEGER 2
: }
13 20: INTEGER 0B C3 8C D2 04 57 E3 58 97 53 6B CB 25 B1 A6 46 30 CC CD 33
35 10: SEQUENCE {
37 8: OBJECT IDENTIFIER ecdsaWithSHA256 (1 2 840 10045 4 3 2)
: }
47 20: SEQUENCE {
49 18: SET {
51 16: SEQUENCE {
53 3: OBJECT IDENTIFIER commonName (2 5 4 3)
58 9: UTF8String 'MALFORMED'
: }
: }
: }
69 30: SEQUENCE {
71 13: UTCTime 27/02/2024 05:15:45 GMT
86 13: UTCTime 21/02/2025 05:15:45 GMT
: }
101 20: SEQUENCE {
103 18: SET {
105 16: SEQUENCE {
107 3: OBJECT IDENTIFIER commonName (2 5 4 3)
112 9: UTF8String 'MALFORMED'
: }
: }
: }
123 331: SEQUENCE {
127 259: SEQUENCE {
131 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
140 247: SEQUENCE {
143 1: INTEGER 1
146 44: SEQUENCE {
148 7: OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1)
157 33: INTEGER
: 00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
: 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
: FF
: }
192 91: SEQUENCE {
194 32: OCTET STRING
: FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00 00
: 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FC
228 32: OCTET STRING
: 5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
: 65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
262 21: BIT STRING
: C4 9D 36 08 86 E7 04 93 6A 66 78 E1 13 9D 26 B7
: 81 9F 7E 90
: }
285 65: OCTET STRING
: 04 6B 17 D1 F2 E1 2C 42 47 F8 BC E6 E5 63 A4 40
: F2 77 03 7D 81 2D EB 33 A0 F4 A1 39 45 D8 98 C2
: 96 4F E3 42 E2 FE 1A 7F 9B 8E E7 EB 4A 7C 0F 9E
: 16 2B CE 33 57 6B 31 5E CE CB B6 40 68 37 BF 51
: F5
352 33: INTEGER
: 00 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
: FF BC E6 FA AD A7 17 9E 84 F3 B9 CA C2 FC 63 25
: 51
387 1: INTEGER 1
: }
: }
390 66: BIT STRING
: 04 BF E0 9C CE BA B7 35 76 23 E5 BF FA 79 CC C0
: 33 F4 5D 3F C7 1F 24 25 13 70 97 36 6F 89 4D 11
: CA 35 13 32 25 15 FA 63 9C B9 44 83 DD 5D FB 1F
: 8D AF 57 26 DE 20 8D 8B 9A CD 2A 3C B8 0A A4 6D
: 1A
: }
458 83: [3] {
460 81: SEQUENCE {
462 29: SEQUENCE {
464 3: OBJECT IDENTIFIER subjectKeyIdentifier (2 5 29 14)
469 22: OCTET STRING
: 04 14 59 7E FB B5 0B AC 9A A6 0A 02 CA B5 B0 C7
: E7 F2 43 DE 4F 27
: }
493 31: SEQUENCE {
495 3: OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35)
500 24: OCTET STRING
: 30 16 80 14 59 7E FB B5 0B AC 9A A6 0A 02 CA B5
: B0 C7 E7 F2 43 DE 4F 27
: }
526 15: SEQUENCE {
528 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19)
533 1: BOOLEAN TRUE
536 5: OCTET STRING 30 03 01 01 FF
: }
: }
: }
: }
543 10: SEQUENCE {
545 8: OBJECT IDENTIFIER ecdsaWithSHA256 (1 2 840 10045 4 3 2)
: }
555 73: BIT STRING
: 30 46 02 21 00 8D F5 38 AD 36 0F 66 8D 41 D2 21
: 0F 64 AA 27 89 8C 9B 60 91 A3 8B 03 57 FF 87 C0
: 6C FE C2 8D 4D 02 21 00 C2 E1 A7 85 20 3E 98 51
: D5 78 64 2D DF 56 37 8A 1C 95 A2 75 33 F7 1E 2D
: C2 95 EA 97 0F 56 4D 49
: }
0 warnings, 0 errors.
Hi, the certificate I used was generated by using the command like:
openssl ecparam -out ec.key -name prime256v1 -genkey -noout -param_enc explicit
openssl req -new -x509 -key ec.key -out cert.pem -days 360 -subj "/CN=TEST/"
Hello, is there any progress on the fix plan? @noloader