import { DerReader } from "../asn1/reader.js"; import { CRYPTO_RSA_CODES, CryptoRsaError } from "../errors/errors.js"; import type { RsaPublicKey } from "./keys.types.js"; /** * Parse a DER-encoded PKCS#1 `RSAPublicKey ::= SEQUENCE { modulus INTEGER, * publicExponent INTEGER }` per RFC 8017 Appendix A.1.1. * * Validates that the public exponent is odd and `>= 3`, matching the * conformance requirement in the spec delta. */ export function parseRsaPublicKeyPkcs1(bytes: Uint8Array): RsaPublicKey { const reader = new DerReader(bytes); const seq = reader.readSequence(); const n = seq.readInteger(); const e = seq.readInteger(); seq.assertEnd(); reader.assertEnd(); return finalisePublicKey(n, e); } /** * Internal: validate `(n, e)` and compute `bitLength`. Used by SPKI / JWK * parsers as well as the PKCS#1 path. */ export function finalisePublicKey(n: bigint, e: bigint): RsaPublicKey { if (n <= 0n) { throw new CryptoRsaError( CRYPTO_RSA_CODES.INVALID_KEY, "error.crypto-rsa.invalid-key.modulus" ); } if (e < 3n) { throw new CryptoRsaError( CRYPTO_RSA_CODES.INVALID_KEY, "error.crypto-rsa.invalid-key.exponent-too-small", { context: { e: e.toString() } } ); } if ((e & 1n) === 0n) { throw new CryptoRsaError( CRYPTO_RSA_CODES.INVALID_KEY, "error.crypto-rsa.invalid-key.exponent-even" ); } const bitLength = n.toString(2).length; return { n, e, bitLength }; }