← All issues

[14] WebCrypto EC SPKI/PKCS8 importer bounds check

Severity: High | Component: WebCore Web Crypto | d3de21e

renderer에서 도달 가능한 parser 버그를 수정하는 패치이므로 High로 평가됩니다. 0xFF length byte가 parse cursor를 buffer 끝 기준 128바이트 이상 이동시킵니다. SPKI 경로에서는 keyData.size() - index에서 unsigned underflow가 발생하고, PKCS8 경로에서는 subvector(index) OOB로 인해 RELEASE_ASSERT를 통한 crash가 발생합니다.

CryptoKeyEC::platformImportSpkiplatformImportPkcs8 모두 bounds check 없이 indexbytesUsedToEncodedLength(keyData[index]) + 1만큼 이동시켰습니다. long-form length byte는 최대 128을 반환하므로, indexkeyData.size()를 크게 초과하게 됩니다.

Source/WebCore/crypto/cocoa/CryptoKeyECCocoa.cpp

index += 1; // BIT STRING 읽기
+ if (index + bytesUsedToEncodedLength(keyData[index]) + 1 > keyData.size())
+ return nullptr;
index += bytesUsedToEncodedLength(keyData[index]) + 1;
auto keySize = keyData.size() - index;

두 importer 모두에서 cursor 이동 직전에 bounds check가 추가되었습니다. 또한 기존 RSA 테스트에 일대일로 대응하는 EC LayoutTest 6개가 추가되었습니다.

공격자 제어 ASN.1 length byte에 대한 advance 후 bounds check 누락 — parse cursor가 buffer 끝을 초과하는 패턴.

SubtleCrypto.importKey는 SPKI (SubjectPublicKeyInfo) 또는 PKCS8 (PrivateKeyInfo) 형식의 바이트 데이터를 입력으로 받습니다. ASN.1 DER length 인코딩은 두 가지로 나뉩니다. 0x80 미만의 byte는 길이를 직접 나타내고, 0x80 이상인 경우에는 이후에 오는 byte 수가 실제 길이 값을 구성합니다. 예를 들어 0xFF는 이후 127바이트가 길이를 인코딩하므로, length field 자체가 최대 128바이트를 차지하게 됩니다. bytesUsedToEncodedLength(b)는 이 length field의 바이트 수를 반환합니다. 한편 Vector<uint8_t>::subvector(offset)offset <= size()RELEASE_ASSERT로 검증합니다.

commit 메시지에 명확히 기재되어 있습니다. 308706@main에서 RSA에 대해 동일한 버그가 수정되었지만, EC 경로에 대한 적용은 빠졌습니다.

layout test에서 확인된 PoC는 0x3000300006072a8648ce3d020106082a8648ce3d03010703ff (25바이트)입니다. 중간 검증을 통과한 뒤, index = 24 + bytesUsedToEncodedLength(0xFF) + 1 = 24 + 128 + 1 = 153으로 계산됩니다. 이때 keyData.size() - index = 25 - 153에서 unsigned underflow가 발생해 ~SIZE_MAX에 도달합니다.

PKCS8 경로에서는 index > keyData.size()인 상태로 keyData.subvector(index)가 호출됩니다. 이때 RELEASE_ASSERT가 발동하여 WebContent process가 중단됩니다. SPKI 경로에서는 underflow된 length 값이 key-size 검증으로 전달됩니다. 이 값이 검증 전에 downstream consumer에서 그대로 신뢰될 경우, 제어 가능한 OOB read로 이어질 가능성이 있습니다. 다만 diff만으로는 이 부분이 직접 확인되지 않습니다.

web에서 직접 도달할 수 있는 parser 경로에 존재하는 이 vulnerability는, renderer process의 가용성과 memory-safety 강화 수준을 약화시킵니다. Web Crypto importer는 pointer/length 산술 연산 이전에 ASN.1 검증을 완료한다는 가정 하에 설계되어 있습니다. 그러나 이번 경우에는 마지막 BIT STRING length byte에서 이 invariant가 성립하지 않았습니다.