1
0

rsaes.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright 2016 Red Hat, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include "misc.h"
  18. #include <jose/b64.h>
  19. #include <jose/jwk.h>
  20. #include "../hooks.h"
  21. #include <jose/openssl.h>
  22. #include <openssl/rand.h>
  23. #include <string.h>
  24. #if defined (EVP_PKEY_CTX_set_rsa_oaep_md) || (OPENSSL_VERSION_NUMBER >= 0x30000000L)
  25. #define NAMES "RSA1_5", "RSA-OAEP", "RSA-OAEP-224", "RSA-OAEP-256", "RSA-OAEP-384", "RSA-OAEP-512"
  26. #define HAVE_OAEP
  27. #else
  28. #define NAMES "RSA1_5"
  29. #define EVP_PKEY_CTX_set_rsa_oaep_md(cfg, md) (-1)
  30. #endif
  31. declare_cleanup(EVP_PKEY_CTX)
  32. declare_cleanup(EVP_PKEY)
  33. static bool
  34. jwk_prep_handles(jose_cfg_t *cfg, const json_t *jwk)
  35. {
  36. const char *alg = NULL;
  37. if (json_unpack((json_t *) jwk, "{s:s}", "alg", &alg) == -1)
  38. return false;
  39. return str2enum(alg, NAMES, NULL) != SIZE_MAX;
  40. }
  41. static bool
  42. jwk_prep_execute(jose_cfg_t *cfg, json_t *jwk)
  43. {
  44. const char *kty = NULL;
  45. if (!jwk_prep_handles(cfg, jwk))
  46. return false;
  47. if (json_unpack(jwk, "{s?s}", "kty", &kty) < 0)
  48. return false;
  49. if (kty && strcmp(kty, "RSA") != 0)
  50. return false;
  51. if (json_object_set_new(jwk, "kty", json_string("RSA")) < 0)
  52. return false;
  53. return true;
  54. }
  55. static const char *
  56. alg_wrap_alg(const jose_hook_alg_t *alg, jose_cfg_t *cfg, const json_t *jwk)
  57. {
  58. const char *name = NULL;
  59. const char *type = NULL;
  60. if (json_unpack((json_t *) jwk, "{s?s,s?s}",
  61. "alg", &name, "kty", &type) < 0)
  62. return NULL;
  63. if (name)
  64. return str2enum(name, NAMES, NULL) != SIZE_MAX ? name : NULL;
  65. if (!type || strcmp(type, "RSA") != 0)
  66. return NULL;
  67. #ifdef HAVE_OAEP
  68. return "RSA-OAEP";
  69. #else
  70. return "RSA1_5";
  71. #endif
  72. }
  73. static const char *
  74. alg_wrap_enc(const jose_hook_alg_t *alg, jose_cfg_t *cfg, const json_t *jwk)
  75. {
  76. size_t len = 0;
  77. len = jose_b64_dec(json_object_get(jwk, "n"), NULL, 0) * 8;
  78. if (len >= 15360)
  79. return "A256CBC-HS512";
  80. else if (len >= 7680)
  81. return "A192CBC-HS384";
  82. else
  83. return "A128CBC-HS256";
  84. }
  85. static bool
  86. alg_wrap_wrp(const jose_hook_alg_t *alg, jose_cfg_t *cfg, json_t *jwe,
  87. json_t *rcp, const json_t *jwk, json_t *cek)
  88. {
  89. openssl_auto(EVP_PKEY_CTX) *epc = NULL;
  90. openssl_auto(EVP_PKEY) *key = NULL;
  91. const EVP_MD *md = NULL;
  92. const RSA *rsa = NULL;
  93. uint8_t *pt = NULL;
  94. uint8_t *ct = NULL;
  95. bool ret = false;
  96. size_t ptl = 0;
  97. size_t ctl = 0;
  98. int tmp = 0;
  99. int pad = 0;
  100. if (!json_object_get(cek, "k") && !jose_jwk_gen(cfg, cek))
  101. return false;
  102. switch (str2enum(alg->name, NAMES, NULL)) {
  103. case 0: pad = RSA_PKCS1_PADDING; tmp = 11; md = EVP_sha1(); break;
  104. case 1: pad = RSA_PKCS1_OAEP_PADDING; tmp = 41; md = EVP_sha1(); break;
  105. case 2: pad = RSA_PKCS1_OAEP_PADDING; tmp = 41; md = EVP_sha224(); break;
  106. case 3: pad = RSA_PKCS1_OAEP_PADDING; tmp = 41; md = EVP_sha256(); break;
  107. case 4: pad = RSA_PKCS1_OAEP_PADDING; tmp = 41; md = EVP_sha384(); break;
  108. case 5: pad = RSA_PKCS1_OAEP_PADDING; tmp = 41; md = EVP_sha512(); break;
  109. default: return false;
  110. }
  111. key = jose_openssl_jwk_to_EVP_PKEY(cfg, jwk);
  112. if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_RSA)
  113. return false;
  114. ptl = jose_b64_dec(json_object_get(cek, "k"), NULL, 0);
  115. if (ptl == SIZE_MAX)
  116. return false;
  117. rsa = EVP_PKEY_get0_RSA(key);
  118. if (!rsa)
  119. return false;
  120. if ((int) ptl >= RSA_size(rsa) - tmp)
  121. return false;
  122. epc = EVP_PKEY_CTX_new(key, NULL);
  123. if (!epc)
  124. return false;
  125. if (EVP_PKEY_encrypt_init(epc) <= 0)
  126. return false;
  127. if (EVP_PKEY_CTX_set_rsa_padding(epc, pad) <= 0)
  128. return false;
  129. if (pad == RSA_PKCS1_OAEP_PADDING) {
  130. if (EVP_PKEY_CTX_set_rsa_oaep_md(epc, md) <= 0)
  131. return false;
  132. if (EVP_PKEY_CTX_set_rsa_mgf1_md(epc, md) <= 0)
  133. return false;
  134. }
  135. pt = malloc(ptl);
  136. if (!pt)
  137. return false;
  138. if (jose_b64_dec(json_object_get(cek, "k"), pt, ptl) != ptl)
  139. goto egress;
  140. if (EVP_PKEY_encrypt(epc, NULL, &ctl, pt, ptl) <= 0)
  141. goto egress;
  142. ct = malloc(ctl);
  143. if (!ct)
  144. goto egress;
  145. if (EVP_PKEY_encrypt(epc, ct, &ctl, pt, ptl) <= 0)
  146. goto egress;
  147. if (json_object_set_new(rcp, "encrypted_key", jose_b64_enc(ct, ctl)) < 0)
  148. goto egress;
  149. ret = add_entity(jwe, rcp, "recipients", "header", "encrypted_key", NULL);
  150. egress:
  151. if (pt) {
  152. OPENSSL_cleanse(pt, ptl);
  153. free(pt);
  154. }
  155. free(ct);
  156. return ret;
  157. }
  158. static bool
  159. alg_wrap_unw(const jose_hook_alg_t *alg, jose_cfg_t *cfg, const json_t *jwe,
  160. const json_t *rcp, const json_t *jwk, json_t *cek)
  161. {
  162. openssl_auto(EVP_PKEY_CTX) *epc = NULL;
  163. openssl_auto(EVP_PKEY) *key = NULL;
  164. const uint8_t *tt = NULL;
  165. const EVP_MD *md = NULL;
  166. uint8_t *ct = NULL;
  167. uint8_t *pt = NULL;
  168. uint8_t *rt = NULL;
  169. bool ret = false;
  170. size_t ctl = 0;
  171. size_t ptl = 0;
  172. size_t rtl = 0;
  173. size_t ttl = 0;
  174. int pad = 0;
  175. switch (str2enum(alg->name, NAMES, NULL)) {
  176. case 0: pad = RSA_PKCS1_PADDING; md = EVP_sha1(); break;
  177. case 1: pad = RSA_PKCS1_OAEP_PADDING; md = EVP_sha1(); break;
  178. case 2: pad = RSA_PKCS1_OAEP_PADDING; md = EVP_sha224(); break;
  179. case 3: pad = RSA_PKCS1_OAEP_PADDING; md = EVP_sha256(); break;
  180. case 4: pad = RSA_PKCS1_OAEP_PADDING; md = EVP_sha384(); break;
  181. case 5: pad = RSA_PKCS1_OAEP_PADDING; md = EVP_sha512(); break;
  182. default: return false;
  183. }
  184. key = jose_openssl_jwk_to_EVP_PKEY(cfg, jwk);
  185. if (!key || EVP_PKEY_base_id(key) != EVP_PKEY_RSA)
  186. goto egress;
  187. ctl = jose_b64_dec(json_object_get(rcp, "encrypted_key"), NULL, 0);
  188. if (ctl == SIZE_MAX)
  189. goto egress;
  190. ct = malloc(ctl);
  191. if (!ct)
  192. goto egress;
  193. if (jose_b64_dec(json_object_get(rcp, "encrypted_key"), ct, ctl) != ctl)
  194. goto egress;
  195. ptl = ctl;
  196. pt = malloc(ptl);
  197. if (!pt)
  198. goto egress;
  199. epc = EVP_PKEY_CTX_new(key, NULL);
  200. if (!epc)
  201. goto egress;
  202. if (EVP_PKEY_decrypt_init(epc) <= 0)
  203. goto egress;
  204. if (EVP_PKEY_CTX_set_rsa_padding(epc, pad) <= 0)
  205. goto egress;
  206. if (pad == RSA_PKCS1_OAEP_PADDING) {
  207. if (EVP_PKEY_CTX_set_rsa_oaep_md(epc, md) <= 0)
  208. goto egress;
  209. if (EVP_PKEY_CTX_set_rsa_mgf1_md(epc, md) <= 0)
  210. goto egress;
  211. }
  212. /* Handle MMA Attack as prescribed by RFC 3218, always generate a
  213. * random buffer of appropriate length so that the same operations
  214. * are performed whether decrypt succeeds or not, in an attempt to
  215. * foil timing attacks */
  216. rtl = ptl;
  217. rt = malloc(rtl);
  218. if (!rt)
  219. goto egress;
  220. if (RAND_bytes(rt, rtl) <= 0)
  221. goto egress;
  222. ret |= EVP_PKEY_decrypt(epc, pt, &ptl, ct, ctl) > 0;
  223. ttl = ret ? ptl : rtl;
  224. tt = ret ? pt : rt;
  225. ret |= pad == RSA_PKCS1_PADDING;
  226. if (json_object_set_new(cek, "k", jose_b64_enc(tt, ttl)) < 0)
  227. ret = false;
  228. egress:
  229. if (pt) {
  230. OPENSSL_cleanse(pt, ptl);
  231. free(pt);
  232. }
  233. if (rt) {
  234. OPENSSL_cleanse(rt, rtl);
  235. free(rt);
  236. }
  237. free(ct);
  238. return ret;
  239. }
  240. static void __attribute__((constructor))
  241. constructor(void)
  242. {
  243. static jose_hook_jwk_t jwk = {
  244. .kind = JOSE_HOOK_JWK_KIND_PREP,
  245. .prep.handles = jwk_prep_handles,
  246. .prep.execute = jwk_prep_execute
  247. };
  248. static jose_hook_alg_t alg[] = {
  249. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  250. .name = "RSA1_5",
  251. .wrap.eprm = "wrapKey",
  252. .wrap.dprm = "unwrapKey",
  253. .wrap.alg = alg_wrap_alg,
  254. .wrap.enc = alg_wrap_enc,
  255. .wrap.wrp = alg_wrap_wrp,
  256. .wrap.unw = alg_wrap_unw },
  257. #ifdef HAVE_OAEP
  258. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  259. .name = "RSA-OAEP",
  260. .wrap.eprm = "wrapKey",
  261. .wrap.dprm = "unwrapKey",
  262. .wrap.alg = alg_wrap_alg,
  263. .wrap.enc = alg_wrap_enc,
  264. .wrap.wrp = alg_wrap_wrp,
  265. .wrap.unw = alg_wrap_unw },
  266. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  267. .name = "RSA-OAEP-224",
  268. .wrap.eprm = "wrapKey",
  269. .wrap.dprm = "unwrapKey",
  270. .wrap.alg = alg_wrap_alg,
  271. .wrap.enc = alg_wrap_enc,
  272. .wrap.wrp = alg_wrap_wrp,
  273. .wrap.unw = alg_wrap_unw },
  274. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  275. .name = "RSA-OAEP-256",
  276. .wrap.eprm = "wrapKey",
  277. .wrap.dprm = "unwrapKey",
  278. .wrap.alg = alg_wrap_alg,
  279. .wrap.enc = alg_wrap_enc,
  280. .wrap.wrp = alg_wrap_wrp,
  281. .wrap.unw = alg_wrap_unw },
  282. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  283. .name = "RSA-OAEP-384",
  284. .wrap.eprm = "wrapKey",
  285. .wrap.dprm = "unwrapKey",
  286. .wrap.alg = alg_wrap_alg,
  287. .wrap.enc = alg_wrap_enc,
  288. .wrap.wrp = alg_wrap_wrp,
  289. .wrap.unw = alg_wrap_unw },
  290. { .kind = JOSE_HOOK_ALG_KIND_WRAP,
  291. .name = "RSA-OAEP-512",
  292. .wrap.eprm = "wrapKey",
  293. .wrap.dprm = "unwrapKey",
  294. .wrap.alg = alg_wrap_alg,
  295. .wrap.enc = alg_wrap_enc,
  296. .wrap.wrp = alg_wrap_wrp,
  297. .wrap.unw = alg_wrap_unw },
  298. #endif
  299. {}
  300. };
  301. jose_hook_jwk_push(&jwk);
  302. for (size_t i = 0; alg[i].name; i++)
  303. jose_hook_alg_push(&alg[i]);
  304. }