hpke_util.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <openssl/core_names.h>
  10. #include <openssl/kdf.h>
  11. #include <openssl/params.h>
  12. #include <openssl/err.h>
  13. #include <openssl/proverr.h>
  14. #include "crypto/hpke.h"
  15. #include "internal/packet.h"
  16. /*
  17. * The largest value happens inside dhkem_extract_and_expand
  18. * Which consists of a max dkmlen of 2*privkeylen + suiteid + small label
  19. */
  20. #define LABELED_EXTRACT_SIZE (10 + 12 + 2 * OSSL_HPKE_MAX_PRIVATE)
  21. /*
  22. * The largest value happens inside dhkem_extract_and_expand
  23. * Which consists of a prklen of secretlen + contextlen of 3 encoded public keys
  24. * + suiteid + small label
  25. */
  26. #define LABELED_EXPAND_SIZE (LABELED_EXTRACT_SIZE + 3 * OSSL_HPKE_MAX_PUBLIC)
  27. /* ASCII: "HPKE-v1", in hex for EBCDIC compatibility */
  28. static const char LABEL_HPKEV1[] = "\x48\x50\x4B\x45\x2D\x76\x31";
  29. static int kdf_derive(EVP_KDF_CTX *kctx,
  30. unsigned char *out, size_t outlen, int mode,
  31. const unsigned char *salt, size_t saltlen,
  32. const unsigned char *ikm, size_t ikmlen,
  33. const unsigned char *info, size_t infolen)
  34. {
  35. int ret;
  36. OSSL_PARAM params[5], *p = params;
  37. *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
  38. if (salt != NULL)
  39. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
  40. (char *)salt, saltlen);
  41. if (ikm != NULL)
  42. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
  43. (char *)ikm, ikmlen);
  44. if (info != NULL)
  45. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
  46. (char *)info, infolen);
  47. *p = OSSL_PARAM_construct_end();
  48. ret = EVP_KDF_derive(kctx, out, outlen, params) > 0;
  49. if (!ret)
  50. ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
  51. return ret;
  52. }
  53. int ossl_hpke_kdf_extract(EVP_KDF_CTX *kctx,
  54. unsigned char *prk, size_t prklen,
  55. const unsigned char *salt, size_t saltlen,
  56. const unsigned char *ikm, size_t ikmlen)
  57. {
  58. return kdf_derive(kctx, prk, prklen, EVP_KDF_HKDF_MODE_EXTRACT_ONLY,
  59. salt, saltlen, ikm, ikmlen, NULL, 0);
  60. }
  61. /* Common code to perform a HKDF expand */
  62. int ossl_hpke_kdf_expand(EVP_KDF_CTX *kctx,
  63. unsigned char *okm, size_t okmlen,
  64. const unsigned char *prk, size_t prklen,
  65. const unsigned char *info, size_t infolen)
  66. {
  67. return kdf_derive(kctx, okm, okmlen, EVP_KDF_HKDF_MODE_EXPAND_ONLY,
  68. NULL, 0, prk, prklen, info, infolen);
  69. }
  70. /*
  71. * See RFC 9180 Section 4 LabelExtract()
  72. */
  73. int ossl_hpke_labeled_extract(EVP_KDF_CTX *kctx,
  74. unsigned char *prk, size_t prklen,
  75. const unsigned char *salt, size_t saltlen,
  76. const unsigned char *suiteid, size_t suiteidlen,
  77. const char *label,
  78. const unsigned char *ikm, size_t ikmlen)
  79. {
  80. int ret = 0;
  81. size_t labeled_ikmlen = 0;
  82. unsigned char labeled_ikm[LABELED_EXTRACT_SIZE];
  83. WPACKET pkt;
  84. /* labeled_ikm = concat("HPKE-v1", suiteid, label, ikm) */
  85. if (!WPACKET_init_static_len(&pkt, labeled_ikm, sizeof(labeled_ikm), 0)
  86. || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, strlen(LABEL_HPKEV1))
  87. || !WPACKET_memcpy(&pkt, suiteid, suiteidlen)
  88. || !WPACKET_memcpy(&pkt, label, strlen(label))
  89. || !WPACKET_memcpy(&pkt, ikm, ikmlen)
  90. || !WPACKET_get_total_written(&pkt, &labeled_ikmlen)
  91. || !WPACKET_finish(&pkt)) {
  92. ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
  93. goto end;
  94. }
  95. ret = ossl_hpke_kdf_extract(kctx, prk, prklen, salt, saltlen,
  96. labeled_ikm, labeled_ikmlen);
  97. end:
  98. WPACKET_cleanup(&pkt);
  99. OPENSSL_cleanse(labeled_ikm, labeled_ikmlen);
  100. return ret;
  101. }
  102. /*
  103. * See RFC 9180 Section 4 LabelExpand()
  104. */
  105. int ossl_hpke_labeled_expand(EVP_KDF_CTX *kctx,
  106. unsigned char *okm, size_t okmlen,
  107. const unsigned char *prk, size_t prklen,
  108. const unsigned char *suiteid, size_t suiteidlen,
  109. const char *label,
  110. const unsigned char *info, size_t infolen)
  111. {
  112. int ret = 0;
  113. size_t labeled_infolen = 0;
  114. unsigned char labeled_info[LABELED_EXPAND_SIZE];
  115. WPACKET pkt;
  116. /* labeled_info = concat(okmlen, "HPKE-v1", suiteid, label, info) */
  117. if (!WPACKET_init_static_len(&pkt, labeled_info, sizeof(labeled_info), 0)
  118. || !WPACKET_put_bytes_u16(&pkt, okmlen)
  119. || !WPACKET_memcpy(&pkt, LABEL_HPKEV1, strlen(LABEL_HPKEV1))
  120. || !WPACKET_memcpy(&pkt, suiteid, suiteidlen)
  121. || !WPACKET_memcpy(&pkt, label, strlen(label))
  122. || !WPACKET_memcpy(&pkt, info, infolen)
  123. || !WPACKET_get_total_written(&pkt, &labeled_infolen)
  124. || !WPACKET_finish(&pkt)) {
  125. ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
  126. goto end;
  127. }
  128. ret = ossl_hpke_kdf_expand(kctx, okm, okmlen,
  129. prk, prklen, labeled_info, labeled_infolen);
  130. end:
  131. WPACKET_cleanup(&pkt);
  132. return ret;
  133. }
  134. /* Common code to create a HKDF ctx */
  135. EVP_KDF_CTX *ossl_kdf_ctx_create(const char *kdfname, const char *mdname,
  136. OSSL_LIB_CTX *libctx, const char *propq)
  137. {
  138. EVP_KDF *kdf;
  139. EVP_KDF_CTX *kctx = NULL;
  140. kdf = EVP_KDF_fetch(libctx, kdfname, propq);
  141. kctx = EVP_KDF_CTX_new(kdf);
  142. EVP_KDF_free(kdf);
  143. if (kctx != NULL && mdname != NULL) {
  144. OSSL_PARAM params[3], *p = params;
  145. if (mdname != NULL)
  146. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
  147. (char *)mdname, 0);
  148. if (propq != NULL)
  149. *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_PROPERTIES,
  150. (char *)propq, 0);
  151. *p = OSSL_PARAM_construct_end();
  152. if (EVP_KDF_CTX_set_params(kctx, params) <= 0) {
  153. EVP_KDF_CTX_free(kctx);
  154. return NULL;
  155. }
  156. }
  157. return kctx;
  158. }