Skip to content

Commit 8c257fa

Browse files
committed
refactor openpgp with parse_ecc_key_tlv
1 parent f7e4049 commit 8c257fa

File tree

1 file changed

+85
-37
lines changed

1 file changed

+85
-37
lines changed

applets/openpgp/openpgp.c

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,86 @@ static int openpgp_sign_or_auth(const CAPDU *capdu, RAPDU *rapdu, bool is_sign)
800800
return 0;
801801
}
802802

803+
// Parse and validate the specific TLV structure for ECC key
804+
static int parse_ecc_key_tlv(const uint8_t *data, size_t data_len, key_type_t key_type, int *public_key_offset) {
805+
const uint8_t *p = data;
806+
size_t remaining = data_len;
807+
int fail;
808+
size_t length_size;
809+
uint16_t length;
810+
811+
// 1. Check Cipher DO (A6)
812+
if (remaining < 1 || *p != 0xA6) {
813+
DBG_MSG("Invalid Cipher DO tag\n");
814+
return -1;
815+
}
816+
p++;
817+
remaining--;
818+
819+
// Get Cipher DO length
820+
length = tlv_get_length_safe(p, remaining, &fail, &length_size);
821+
if (fail || length > remaining - length_size) {
822+
DBG_MSG("Invalid Cipher DO length\n");
823+
return -1;
824+
}
825+
p += length_size;
826+
remaining -= length_size;
827+
828+
// 2. Check Public Key DO (7F49)
829+
if (remaining < 2 || *p != 0x7F || *(p + 1) != 0x49) {
830+
DBG_MSG("Invalid Public Key DO\n");
831+
return -1;
832+
}
833+
p += 2; // Skip 7F49 tag
834+
remaining -= 2;
835+
836+
// Get Public Key DO length
837+
length = tlv_get_length_safe(p, remaining, &fail, &length_size);
838+
if (fail || length > remaining - length_size) {
839+
DBG_MSG("Invalid Public Key DO length\n");
840+
return -1;
841+
}
842+
p += length_size;
843+
remaining -= length_size;
844+
845+
// 3. Check External Public Key (86)
846+
if (remaining < 1 || *p != 0x86) {
847+
DBG_MSG("Invalid External Public Key\n");
848+
return -1;
849+
}
850+
p++;
851+
remaining--;
852+
853+
// Get External Public Key length
854+
length = tlv_get_length_safe(p, remaining, &fail, &length_size);
855+
if (fail || length > remaining - length_size) {
856+
DBG_MSG("Invalid External Public Key length\n");
857+
return -1;
858+
}
859+
p += length_size;
860+
remaining -= length_size;
861+
862+
// 4. Validate key data based on key type
863+
uint16_t expected_pubkey_len = PUBLIC_KEY_LENGTH[key_type];
864+
865+
// For Short Weierstrass curves (SECP*, BP*), we need the 0x04 prefix
866+
if (IS_SHORT_WEIERSTRASS(key_type)) {
867+
if (length != expected_pubkey_len + 1 || *p != 0x04) {
868+
DBG_MSG("Invalid public key format for Short Weierstrass curve\n");
869+
return -1;
870+
}
871+
*public_key_offset = (p - data) + 1; // Skip 0x04 prefix
872+
} else { // For X25519
873+
if (length != expected_pubkey_len) {
874+
DBG_MSG("Invalid public key length for X25519\n");
875+
return -1;
876+
}
877+
*public_key_offset = p - data;
878+
}
879+
880+
return 0;
881+
}
882+
803883
static int openpgp_decipher(const CAPDU *capdu, RAPDU *rapdu) {
804884
#ifndef FUZZ
805885
if (PW1_MODE82() == 0) EXCEPT(SW_SECURITY_STATUS_NOT_SATISFIED);
@@ -861,43 +941,11 @@ static int openpgp_decipher(const CAPDU *capdu, RAPDU *rapdu) {
861941

862942
int public_key_offset;
863943

864-
if (key.meta.type == SECP521R1) {
865-
if (DATA[0] != 0xA6 ||
866-
DATA[1] != 0x81 || DATA[2] != PUBLIC_KEY_LENGTH[key.meta.type] + 8 ||
867-
DATA[3] != 0x7F || DATA[4] != 0x49 ||
868-
DATA[5] != 0x81 || DATA[6] != PUBLIC_KEY_LENGTH[key.meta.type] + 4 ||
869-
DATA[7] != 0x86 ||
870-
DATA[8] != 0x81 || DATA[9] != PUBLIC_KEY_LENGTH[key.meta.type] + 1 ||
871-
DATA[10] != 0x04) {
872-
DBG_MSG("Incorrect data\n");
873-
memzero(&key, sizeof(key));
874-
EXCEPT(SW_WRONG_DATA);
875-
}
876-
public_key_offset = 11;
877-
} else {
878-
if (DATA[0] != 0xA6 || DATA[2] != 0x7F || DATA[3] != 0x49 || DATA[5] != 0x86) {
879-
DBG_MSG("Incorrect data\n");
880-
memzero(&key, sizeof(key));
881-
EXCEPT(SW_WRONG_DATA);
882-
}
883-
884-
if (IS_SHORT_WEIERSTRASS(key.meta.type)) {
885-
if (DATA[1] != PUBLIC_KEY_LENGTH[key.meta.type] + 6 || DATA[4] != PUBLIC_KEY_LENGTH[key.meta.type] + 3 ||
886-
DATA[6] != PUBLIC_KEY_LENGTH[key.meta.type] + 1 || DATA[7] != 0x04) {
887-
DBG_MSG("Incorrect length data\n");
888-
memzero(&key, sizeof(key));
889-
EXCEPT(SW_WRONG_DATA);
890-
}
891-
public_key_offset = 8;
892-
} else {
893-
if (DATA[1] != PUBLIC_KEY_LENGTH[key.meta.type] + 5 || DATA[4] != PUBLIC_KEY_LENGTH[key.meta.type] + 2 ||
894-
DATA[6] != PUBLIC_KEY_LENGTH[key.meta.type]) {
895-
DBG_MSG("Incorrect length data\n");
896-
memzero(&key, sizeof(key));
897-
EXCEPT(SW_WRONG_DATA);
898-
}
899-
public_key_offset = 7;
900-
}
944+
// Use our new TLV parsing function to process the data
945+
if (parse_ecc_key_tlv(DATA, LC, key.meta.type, &public_key_offset) < 0) {
946+
DBG_MSG("Incorrect TLV data structure\n");
947+
memzero(&key, sizeof(key));
948+
EXCEPT(SW_WRONG_DATA);
901949
}
902950

903951
if (ecdh(key.meta.type, key.ecc.pri, DATA + public_key_offset, RDATA) < 0) {

0 commit comments

Comments
 (0)