JWK OEAP importKey fails if p < q

Number:rdar://34916499 Date Originated:2017-10-10
Status: Resolved:
Product:Safari Product Version:11.0 (13604.
Classification: Reproducible:Yes
When importing a JWK OEAP private key using crypto.subtle.importKey the import will fail if p < q

Steps to Reproduce:

In JavaScript Console

let key = {
    "alg": "RSA-OAEP",
    "d": "AEhCO0ZRRbsKTbTOzgW8_q2pET2vLQOyaLBwhWw6fK6Zz4GkKhNzcd15HpjQ5_HsqancBl6NT0h0RZ-NATzo4nTW-UL7HS3KfX4MBeun8s09LUQGFiteBbodONlnImL298JOeQnJiCtTyOPp7BokFvH5Tx0p5iSaMHQ9t6mo3CQ5EqM5tCOOAAIhIKfaTYACIA3z1ofKr45tHaqtdFNtGmEzlXjFGc_7AwK_TfaXJfcqyLaLqp7llc0c7Pktj-eSV4FI_Oysb0LXDK-L5ehJPafz6p9pLXCaQTOULMfwbvv3xKlY6Q2a9-AoBDWPPTgNzMS7DojCDguLA98-4ehjQQ",
    "dp": "YRLeNGJByvFv4Jpv2Ef-mmknlNmZdg2MCk7xsQh3-nufKxEssdN_jTF1lTR5mnYKJyaGfsuADRy-xzIuili91xx2631VXIpzO4EApt-_droErdjzwJiOVqbMQmEU9ithLWWbpa0IPm5HZCa7PD-2ctt79aMFualsmwQ2Auc2ET0",
    "dq": "KbWh0933yZ1ndCe5KW_QF0RlF57QsLL3Lc6bfOB2uY9AitUv5s4Q0BrHwdlS-0v1S0s3T_XJKjN5XRd-TEGOX0xZMRGuA99QyGm_arw4Rkrm27u3zBBUaN5Hm1rHMYugrbb4Ch1BQioCdlR1yfJwVR5w8cpp6J68jWl1ST0Oj7k",
    "e": "AQAB",
    "ext": true,
    "key_ops": [
    "kty": "RSA",
    "n": "zYn-rDpx6iI7AylGoNVh5WtdlgyQNa63JIv562B0Xh3Ye5ip3MW_ehPeEOIkTFFfigTNc2stCrTHVNRGgpny0bRsYJT6w_8PBzeCwIJ4xMy9Kzy8SGbyC8QfL0nopUJuJcIU5EuTyY4XX9p9M2FBqtjmplKGj6XsP81JrpVl1ZN5CNFW1mmpEIjdc7egzlH0CaJGum-Opr8rSw_-SQQNEDWsftAPwZktrJlk_mL068o6wuPuSgrzhhesbxBC532SsWtVkIgbJy-UlcsTI6KCSxZHQiAJ0q37bf1535IF8okrVd6iJqUjZ2XltbZpxDkAtoTKBEpH3tBiMUhiUzkOTQ",
    "p": "1blRZM5aXP7CkdOTWidcnkZQiBk8Rnpl12p2AsDgCqBWeLtGOoi8lux5zPwK07cB5Mcf0r7_uLHQt0tPHfuDKMacktLUsoCsVDbnkOPJL9aK0nWLCMzy9sgmZq4LMOChNRzPkQegq-vJxXON_Ol_3O2YGlePnpIIT79V_CzDbuU",
    "q": "9jI1BOgJNo6P3U21dgEYiMjJhF38n1xiyxRjl_dp5otzN4mkpg32sGAZAhO1rdjc9Zz2OlvuMyef6YQrtcDuVcm8Sq2YyYwhqB6dlN6dKswr9gGyBEqfcUtKoGRm7uNA1_z_N83n9h1ji06958uq3S3QvSS4_FlNlvQMsoOOw0k",
    "qi": "x9wUQzvMTSkzPKgvMnGxhltqX6Q3ruv2O5M98Vg-f_-c4O3p-bFSO94768OV7859QD_LY7J0eqjaUtvXXMcHpOH0J8xa7vgVU37vEjqEwI_zloDkyRihumwFKH6SCRTZTnIlJNgNFR_m1fFhatHdQj6VFf0HYREnTqlWd25yYRE",
    "kid": "h7bbt47gymfxtb3amihkvgu6zi"
let alg = {
	name: "RSA-OAEP",
	modulusLength: 2048,
	publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 24-bit representation of 65537
	hash: {name: "SHA-1"}
crypto.subtle.importKey("jwk", key, alg, true, ["decrypt"]);

Expected Results:

A successful cryptoky

Actual Results:

Error stating

"Unhandled Promise Rejection: DataError (DOM Exception 30): Data provided to an operation does not meet requirements"


Looking at the corecrypto source in cc_rsa_generate_key.c

/* qInv = q^(-1) mod p. This requires q to be at least as long as p with
    proper zero padding. Our caller takes care if this. Obviously qInv can
    be as big as p too. */
    if (cczp_mod_inv(zp, qinv, cczp_prime(zq)))

So if this is what is eventually called, it does have the expectation that p > q, and says it is the caller's responsibility.

May conform to RFC

There is a case that can be made that the behavior that we see as buggy may be correct behavior. RFC 3447 doesn't explicitly say that p must be greater than q. However having p < q may cause things to go against the RFC, which states.


the CRT coefficient qInv is a positive integer less than p satisfying

   q * qInv == 1 (mod p).


If p > q, the the most natural way to compute qInv will lead to one that is positive and less than p. But if p < q, the most natural way of computing qInv will lead to a negative value. Furthermore most browsers only or mostly generate OAEP private keys in which p > q. (Edge appears to be the exception.)

However, we've found that other browsers accept private keys with p < q. And arguing based on "the most natural way" to compute qInv seems like a stretch. There is also a very "natural" correction that gives you a positive qInv.

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!