49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
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 };
|
|
}
|