If the C<priv-only> format is not included in the list, this format will not be
recognised on input.
-=item C<priv-oqs>:
-
-This format represents B<PKCS#8> objects in which the private key is a DER
-encoding of an octet string containing the FIPS 203 decapsulation key B<dk>.
-This format is used in some builds of the C<oqsprovider>.
-If the C<priv-oqs> format is not included in the list, this format will not be
-recognised on input.
-
-=item C<pair-oqs>:
+=item C<oqskeypair>:
This format represents B<PKCS#8> objects in which the private key is a DER
encoding of an octet string containing the concatenaton of the FIPS 203
decapsulation key B<dk> and the encapsulation key B<ek>.
This encoding is used in some builds of the C<oqsprovider>.
-If the C<pair-oqs> format is not included in the list, this format will not be
+If the C<oqskeypair> format is not included in the list, this format will not be
recognised on input.
=item C<bare-seed>:
when available, otherwise the output will have just the key.
If C<priv-only> is listed first, then just the key is output regardless of
whether the seed is present.
-The legacy C<oqs> and C<bare> formats can also be output, by listing those
-first.
+The legacy C<oqskeypair>, C<bare-seed> and C<bare-priv> formats can also be
+output, by listing those first.
=back
* For each parameter set we support a few PKCS#8 input formats, three
* corresponding to the "either or both" variants of:
*
- * ML-KEM-PrivateKey ::= SEQUENCE {
- * seed OCTET STRING SIZE (64) OPTIONAL,
- * expandedKey [1] IMPLICIT OCTET STRING SIZE (1632 | 2400 | 3172) OPTIONAL }
- * (WITH COMPONENTS {..., seed PRESENT } |
- * WITH COMPONENTS {..., expandedKey PRESENT })
+ * ML-KEM-PrivateKey ::= CHOICE {
+ * seed [0] IMPLICIT OCTET STRING SIZE (64),
+ * expandedKey OCTET STRING SIZE (1632 | 2400 | 3168)
+ * both SEQUENCE {
+ * seed OCTET STRING SIZE (64),
+ * expandedKey OCTET STRING SIZE (1632 | 2400 | 3168) } }
*
- * and two more for historical OQS encodings.
+ * one more for a historical OQS encoding:
*
- * - OQS private key: OCTET STRING
* - OQS private + public key: OCTET STRING
* (The public key is ignored, just as with PKCS#8 v2.)
*
- * and two more that are "inspired" by the IETF non-ASN.1 seed encoding.
+ * and two more that are the minimal IETF non-ASN.1 seed encoding:
*
* - Bare seed (just the 64 bytes)
* - Bare priv (just the key bytes)
*
- * An offset of zero means that particular field is absent.
+ * A length of zero means that particular field is absent.
+ *
+ * The p8_shift is 0 when the top-level tag+length occupy four bytes, 2 when
+ * they occupy two by†es, and 4 when no tag is used at all.
*
* On output the PKCS8 info table order is important:
* - When we have a seed we'll use the first entry with a non-zero seed offset.
* - Otherwise, the first entry with a zero seed offset.
*
* As written, when possible, we prefer to output both the seed and private
- * key, otherwise, just the private key ([1] IMPLICIT OCTET STRING form).
+ * key, otherwise, just the private key.
*
* The various lengths in the PKCS#8 tag/len fields could have been left
* zeroed, and filled in on the fly from the algorithm parameters, but that
* into the tables. Had they been zeroed, one table could cover all three
* ML-KEM parameter sets.
*/
-#define NUM_PKCS8_FORMATS 7
+#define NUM_PKCS8_FORMATS 6
/*-
* ML-KEM-512:
* Public key bytes: 800 (0x0320)
* Private key bytes: 1632 (0x0660)
*/
-static const ML_KEM_SPKI_INFO ml_kem_512_spki_info = {
+static const ML_KEM_SPKI_FMT ml_kem_512_spkifmt = {
{ 0x30, 0x82, 0x03, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x01, 0x03, 0x82, 0x03, 0x21, 0x00, }
};
-static const ML_KEM_PKCS8_INFO ml_kem_512_pkcs8_info[] = {
- { "seed-priv", 0x06aa, 0x308206a6, 0x0440, 6, 0x40, 0x81820660, 0x4a, 0x0660, 0x0000, 0x0000 },
- { "priv-only", 0x0668, 0x30820664, 0, 0, 0x00, 0x81820660, 0x08, 0x0660, 0x0000, 0x0000 },
- { "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "priv-oqs", 0x0664, 0x04820660, 0, 0, 0x00, 0x04820660, 0x04, 0x0660, 0x0000, 0x0000 },
- { "pair-oqs", 0x0984, 0x04820980, 0, 0, 0x00, 0x04820980, 0x04, 0x0660, 0x0664, 0x0320 },
- { "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "bare-priv", 0x0660, 0, 0, 0, 0x00, 0, 0x00, 0x0660, 0x0000, 0x0000 },
+static const ML_KEM_PKCS8_FMT ml_kem_512_p8fmt[NUM_PKCS8_FORMATS] = {
+ { "seed-priv", 0x06aa, 0, 0x308206a6, 0x0440, 6, 0x40, 0x04820660, 0x4a, 0x0660, 0, 0 },
+ { "priv-only", 0x0664, 0, 0x04820660, 0, 0, 0, 0, 0x04, 0x0660, 0, 0 },
+ { "oqskeypair", 0x0984, 0, 0x04820980, 0, 0, 0, 0, 0x04, 0x0660, 0x0664, 0x0320 },
+ { "seed-only", 0x0042, 2, 0x8040, 0, 2, 0x40, 0, 0, 0, 0, 0 },
+ { "bare-priv", 0x0660, 4, 0, 0, 0, 0, 0, 0, 0x0660, 0, 0 },
+ { "bare-seed", 0x0040, 4, 0, 0, 0, 0x40, 0, 0, 0, 0, 0 },
};
/*-
* Public key bytes: 1184 (0x04a0)
* Private key bytes: 2400 (0x0960)
*/
-static const ML_KEM_SPKI_INFO ml_kem_768_spki_info = {
+static const ML_KEM_SPKI_FMT ml_kem_768_spkifmt = {
{ 0x30, 0x82, 0x04, 0xb2, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x02, 0x03, 0x82, 0x04, 0xa1, 0x00, }
};
-static const ML_KEM_PKCS8_INFO ml_kem_768_pkcs8_info[] = {
- { "seed-priv", 0x09aa, 0x308209a6, 0x0440, 6, 0x40, 0x81820960, 0x4a, 0x0960, 0x0000, 0x0000 },
- { "priv-only", 0x0968, 0x30820964, 0, 0, 0x00, 0x81820960, 0x08, 0x0960, 0x0000, 0x0000 },
- { "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "priv-oqs", 0x0964, 0x04820960, 0, 0, 0x00, 0x04820960, 0x04, 0x0960, 0x0000, 0x0000 },
- { "pair-oqs", 0x0e04, 0x04820e00, 0, 0, 0x00, 0x04820e00, 0x04, 0x0960, 0x0964, 0x04a0 },
- { "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "bare-priv", 0x0960, 0, 0, 0, 0x00, 0, 0x00, 0x0960, 0x0000, 0x0000 },
+static const ML_KEM_PKCS8_FMT ml_kem_768_p8fmt[NUM_PKCS8_FORMATS] = {
+ { "seed-priv", 0x09aa, 0, 0x308209a6, 0x0440, 6, 0x40, 0x04820960, 0x4a, 0x0960, 0, 0, },
+ { "priv-only", 0x0964, 0, 0x04820960, 0, 0, 0, 0, 0x04, 0x0960, 0, 0, },
+ { "oqskeypair", 0x0e04, 0, 0x04820e00, 0, 0, 0, 0, 0x04, 0x0960, 0x0964, 0x04a0 },
+ { "seed-only", 0x0042, 2, 0x8040, 0, 2, 0x40, 0, 0, 0, 0, 0, },
+ { "bare-priv", 0x0960, 4, 0, 0, 0, 0, 0, 0, 0x0960, 0, 0, },
+ { "bare-seed", 0x0040, 4, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, },
};
/*-
* Private key bytes: 3168 (0x0c60)
* Public key bytes: 1568 (0x0620)
*/
-static const ML_KEM_SPKI_INFO ml_kem_1024_spki_info = {
+static const ML_KEM_SPKI_FMT ml_kem_1024_spkifmt = {
{ 0x30, 0x82, 0x06, 0x32, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x04, 0x03, 0x03, 0x82, 0x06, 0x21, 0x00, }
};
-static const ML_KEM_PKCS8_INFO ml_kem_1024_pkcs8_info[] = {
- { "seed-priv", 0x0caa, 0x30820ca6, 0x0440, 6, 0x40, 0x81820c60, 0x4a, 0x0c60, 0x0000, 0x0000 },
- { "priv-only", 0x0c68, 0x30820c64, 0, 0, 0x00, 0x81820c60, 0x08, 0x0c60, 0x0000, 0x0000 },
- { "seed-only", 0x0044, 0x30420440, 0, 4, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "priv-oqs", 0x0c64, 0x04820c60, 0, 0, 0x00, 0x04820c60, 0x04, 0x0c60, 0x0000, 0x0000 },
- { "pair-oqs", 0x1284, 0x04821280, 0, 0, 0x00, 0x04821280, 0x04, 0x0c60, 0x0c64, 0x0620 },
- { "bare-seed", 0x0040, 0, 0, 0, 0x40, 0, 0x00, 0x0000, 0x0000, 0x0000 },
- { "bare-priv", 0x0c60, 0, 0, 0, 0x00, 0, 0x00, 0x0c60, 0x0000, 0x0000 },
+static const ML_KEM_PKCS8_FMT ml_kem_1024_p8fmt[NUM_PKCS8_FORMATS] = {
+ { "seed-priv", 0x0caa, 0, 0x30820ca6, 0x0440, 6, 0x40, 0x04820c60, 0x4a, 0x0c60, 0, 0 },
+ { "priv-only", 0x0c64, 0, 0x04820c60, 0, 0, 0, 0, 0x04, 0x0c60, 0, 0 },
+ { "oqskeypair", 0x1284, 0, 0x04821280, 0, 0, 0, 0, 0x04, 0x0c60, 0x0c64, 0x0620 },
+ { "seed-only", 0x0042, 2, 0x8040, 0, 2, 0x40, 0, 0, 0, 0, 0 },
+ { "bare-priv", 0x0c60, 4, 0, 0, 0, 0, 0, 0, 0x0c60, 0, 0 },
+ { "bare-seed", 0x0040, 4, 0, 0, 0, 0x40, 0, 0, 0, 0, 0 },
};
/* Indices of slots in the `codecs` table below */
* Per-variant fixed parameters
*/
static const ML_KEM_CODEC codecs[3] = {
- { &ml_kem_512_spki_info, ml_kem_512_pkcs8_info },
- { &ml_kem_768_spki_info, ml_kem_768_pkcs8_info },
- { &ml_kem_1024_spki_info, ml_kem_1024_pkcs8_info }
+ { &ml_kem_512_spkifmt, ml_kem_512_p8fmt },
+ { &ml_kem_768_spkifmt, ml_kem_768_p8fmt },
+ { &ml_kem_1024_spkifmt, ml_kem_1024_p8fmt }
};
/* Retrieve the parameters of one of the ML-KEM variants */
return NULL;
}
-static int vp8_pref_cmp(const void *va, const void *vb)
+static int pref_cmp(const void *va, const void *vb)
{
- const ML_KEM_PKCS8_PREF *a = va;
- const ML_KEM_PKCS8_PREF *b = vb;
+ const ML_KEM_PKCS8_FMT_PREF *a = va;
+ const ML_KEM_PKCS8_FMT_PREF *b = vb;
/*
* Zeros sort last, otherwise the sort is in increasing order.
* as required by qsort(3). When overflow or underflow is possible, the
* correct transitive comparison would be: (b < a) - (a < b).
*/
- if (a->vp8_pref > 0 && b->vp8_pref > 0)
- return a->vp8_pref - b->vp8_pref;
+ if (a->pref > 0 && b->pref > 0)
+ return a->pref - b->pref;
/* A preference of 0 is "larger" than (sorts after) any nonzero value. */
- return b->vp8_pref - a->vp8_pref;
+ return b->pref - a->pref;
}
-static ML_KEM_PKCS8_PREF *vp8_order(const char *algorithm_name,
- const ML_KEM_PKCS8_INFO *pkcs8_info,
- const char *direction, const char *formats)
+static
+ML_KEM_PKCS8_FMT_PREF *vp8_order(const char *algorithm_name,
+ const ML_KEM_PKCS8_FMT *p8fmt,
+ const char *direction, const char *formats)
{
- ML_KEM_PKCS8_PREF *ret;
+ ML_KEM_PKCS8_FMT_PREF *ret;
int i, count = 0;
const char *fmt = formats, *end;
const char *sep = "\t ,";
- /* Reserve an extra terminal slot with vp8_entry == NULL */
+ /* Reserve an extra terminal slot with fmt == NULL */
if ((ret = OPENSSL_zalloc((NUM_PKCS8_FORMATS + 1) * sizeof(*ret))) == NULL)
return NULL;
/* Entries that match a format will get a non-zero preference. */
for (i = 0; i < NUM_PKCS8_FORMATS; ++i) {
- ret[i].vp8_entry = &pkcs8_info[i];
- ret[i].vp8_pref = 0;
+ ret[i].fmt = &p8fmt[i];
+ ret[i].pref = 0;
}
/* Default to compile-time table order when none specified. */
end = fmt + strcspn(fmt, sep);
for (i = 0; i < NUM_PKCS8_FORMATS; ++i) {
/* Skip slots already selected or with a different name. */
- if (ret[i].vp8_pref > 0
- || OPENSSL_strncasecmp(ret[i].vp8_entry->p8_name,
+ if (ret[i].pref > 0
+ || OPENSSL_strncasecmp(ret[i].fmt->p8_name,
fmt, (end - fmt)) != 0)
continue;
/* First time match */
- ret[i].vp8_pref = ++count;
+ ret[i].pref = ++count;
break;
}
fmt = end;
return NULL;
}
/* Sort by preference, with 0's last */
- qsort(ret, NUM_PKCS8_FORMATS, sizeof(*ret), vp8_pref_cmp);
+ qsort(ret, NUM_PKCS8_FORMATS, sizeof(*ret), pref_cmp);
/* Terminate the list at first unselected entry, perhaps reserved slot. */
- ret[count].vp8_entry = NULL;
+ ret[count].fmt = NULL;
return ret;
}
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_KEM_VINFO *v;
const ML_KEM_CODEC *codec;
- const ML_KEM_SPKI_INFO *vspki;
+ const ML_KEM_SPKI_FMT *vspki;
ML_KEM_KEY *ret;
if ((v = ossl_ml_kem_get_vinfo(evp_type)) == NULL
|| (codec = ml_kem_get_codec(evp_type)) == NULL)
return NULL;
- vspki = codec->spki_info;
+ vspki = codec->spkifmt;
if (publen != ML_KEM_SPKI_OVERHEAD + (ossl_ssize_t) v->pubkey_bytes
|| memcmp(pubenc, vspki->asn1_prefix, ML_KEM_SPKI_OVERHEAD) != 0)
return NULL;
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
const ML_KEM_VINFO *v;
const ML_KEM_CODEC *codec;
- ML_KEM_PKCS8_PREF *vp8_alloc = NULL, *vp8_slot;
- const ML_KEM_PKCS8_INFO *vp8;
+ ML_KEM_PKCS8_FMT_PREF *fmt_slots = NULL, *slot;
+ const ML_KEM_PKCS8_FMT *p8fmt;
ML_KEM_KEY *key = NULL, *ret = NULL;
PKCS8_PRIV_KEY_INFO *p8inf = NULL;
const uint8_t *buf, *pos;
const X509_ALGOR *alg = NULL;
const char *formats;
int len, ptype;
- uint32_t magic, p8_magic;
+ uint32_t magic;
uint16_t seed_magic;
/* Which ML-KEM variant? */
/* Get the list of enabled decoders. Their order is not important here. */
formats = ossl_prov_ctx_get_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_INPUT_FORMATS, NULL);
- vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, codec->pkcs8_info,
- "input", formats);
- if (vp8_alloc == NULL)
+ fmt_slots = vp8_order(v->algorithm_name, codec->p8fmt,
+ "input", formats);
+ if (fmt_slots == NULL)
goto end;
/* Parameters must be absent. */
/* Find the matching p8 info slot, that also has the expected length. */
pos = OPENSSL_load_u32_be(&magic, buf);
- for (vp8_slot = vp8_alloc; vp8_slot->vp8_entry != NULL; ++vp8_slot) {
- if (len != (ossl_ssize_t)vp8_slot->vp8_entry->p8_bytes)
+ for (slot = fmt_slots; (p8fmt = slot->fmt) != NULL; ++slot) {
+ if (len != (ossl_ssize_t)p8fmt->p8_bytes)
continue;
- /* p8_magic == 0, signals a non-ASN.1 length-based encoding */
- if ((p8_magic = vp8_slot->vp8_entry->p8_magic) == 0) {
- pos = buf;
+ if (p8fmt->p8_shift == sizeof(magic)
+ || (magic >> (p8fmt->p8_shift * 8)) == p8fmt->p8_magic) {
+ pos -= p8fmt->p8_shift;
break;
}
- if (magic == p8_magic)
- break;
}
- if ((vp8 = vp8_slot->vp8_entry) == NULL
- || (vp8->seed_length > 0 && vp8->seed_length != ML_KEM_SEED_BYTES)
- || (vp8->priv_length > 0 && vp8->priv_length != v->prvkey_bytes)
- || (vp8->pub_length > 0 && vp8->pub_length != v->pubkey_bytes)) {
+ if (p8fmt == NULL
+ || (p8fmt->seed_length > 0 && p8fmt->seed_length != ML_KEM_SEED_BYTES)
+ || (p8fmt->priv_length > 0 && p8fmt->priv_length != v->prvkey_bytes)
+ || (p8fmt->pub_length > 0 && p8fmt->pub_length != v->pubkey_bytes)) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_ML_KEM_NO_FORMAT,
"no matching enabled %s private key input formats",
v->algorithm_name);
goto end;
}
- if (vp8->seed_length > 0) {
+ if (p8fmt->seed_length > 0) {
/* Check |seed| tag/len, if not subsumed by |magic|. */
- if (pos + sizeof(uint16_t) == buf + vp8->seed_offset) {
+ if (pos + sizeof(uint16_t) == buf + p8fmt->seed_offset) {
pos = OPENSSL_load_u16_be(&seed_magic, pos);
- if (seed_magic != vp8->seed_magic)
+ if (seed_magic != p8fmt->seed_magic)
goto end;
- } else if (pos != buf + vp8->seed_offset) {
+ } else if (pos != buf + p8fmt->seed_offset) {
goto end;
}
pos += ML_KEM_SEED_BYTES;
}
- if (vp8->priv_length > 0) {
+ if (p8fmt->priv_length > 0) {
/* Check |priv| tag/len */
- if (pos + sizeof(uint32_t) == buf + vp8->priv_offset) {
+ if (pos + sizeof(uint32_t) == buf + p8fmt->priv_offset) {
pos = OPENSSL_load_u32_be(&magic, pos);
- if (magic != vp8->priv_magic)
+ if (magic != p8fmt->priv_magic)
goto end;
- } else if (pos != buf + vp8->priv_offset) {
+ } else if (pos != buf + p8fmt->priv_offset) {
goto end;
}
pos += v->prvkey_bytes;
}
- if (vp8->pub_length > 0) {
- if (pos != buf + vp8->pub_offset)
+ if (p8fmt->pub_length > 0) {
+ if (pos != buf + p8fmt->pub_offset)
goto end;
pos += v->pubkey_bytes;
}
provctx, OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED, 1);
key->prefer_seed = ossl_prov_ctx_get_bool_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED, 1);
- if (vp8->seed_length > 0) {
- if (!ossl_ml_kem_set_seed(buf + vp8->seed_offset,
+ if (p8fmt->seed_length > 0) {
+ if (!ossl_ml_kem_set_seed(buf + p8fmt->seed_offset,
ML_KEM_SEED_BYTES, key)) {
ERR_raise_data(ERR_LIB_OSSL_DECODER, ERR_R_INTERNAL_ERROR,
"error storing %s private key seed",
goto end;
}
}
- if (vp8->priv_length > 0) {
- if ((key->encoded_dk = OPENSSL_malloc(vp8->priv_length)) == NULL) {
+ if (p8fmt->priv_length > 0) {
+ if ((key->encoded_dk = OPENSSL_malloc(p8fmt->priv_length)) == NULL) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
"error parsing %s private key",
v->algorithm_name);
goto end;
}
- memcpy(key->encoded_dk, buf + vp8->priv_offset, vp8->priv_length);
+ memcpy(key->encoded_dk, buf + p8fmt->priv_offset, p8fmt->priv_length);
}
/* Any OQS public key content is ignored */
ret = key;
end:
- OPENSSL_free(vp8_alloc);
+ OPENSSL_free(fmt_slots);
PKCS8_PRIV_KEY_INFO_free(p8inf);
if (ret == NULL)
ossl_ml_kem_key_free(key);
{
const ML_KEM_VINFO *v = key->vinfo;
const ML_KEM_CODEC *codec;
- ML_KEM_PKCS8_PREF *vp8_alloc, *vp8_slot;
- const ML_KEM_PKCS8_INFO *vp8;
+ ML_KEM_PKCS8_FMT_PREF *fmt_slots, *slot;
+ const ML_KEM_PKCS8_FMT *p8fmt;
uint8_t *buf = NULL, *pos;
const char *formats;
int len = ML_KEM_SEED_BYTES;
formats = ossl_prov_ctx_get_param(
provctx, OSSL_PKEY_PARAM_ML_KEM_OUTPUT_FORMATS, NULL);
- vp8_slot = vp8_alloc = vp8_order(v->algorithm_name, codec->pkcs8_info,
- "output", formats);
- if (vp8_alloc == NULL)
+ fmt_slots = vp8_order(v->algorithm_name, codec->p8fmt,
+ "output", formats);
+ if (fmt_slots == NULL)
return 0;
/* If we don't have a seed, skip seedful entries */
- if (!ossl_ml_kem_have_seed(key))
- while (vp8_slot->vp8_entry != NULL
- && vp8_slot->vp8_entry->seed_length != 0)
- ++vp8_slot;
+ for (slot = fmt_slots; (p8fmt = slot->fmt) != NULL; ++slot)
+ if (ossl_ml_kem_have_seed(key) || p8fmt->seed_length == 0)
+ break;
/* No matching table entries, give up */
- if ((vp8 = vp8_slot->vp8_entry) == NULL
- || (vp8->seed_length > 0 && vp8->seed_length != ML_KEM_SEED_BYTES)
- || (vp8->priv_length > 0 && vp8->priv_length != v->prvkey_bytes)
- || (vp8->pub_length > 0 && vp8->pub_length != v->pubkey_bytes)) {
+ if (p8fmt == NULL
+ || (p8fmt->seed_length > 0 && p8fmt->seed_length != ML_KEM_SEED_BYTES)
+ || (p8fmt->priv_length > 0 && p8fmt->priv_length != v->prvkey_bytes)
+ || (p8fmt->pub_length > 0 && p8fmt->pub_length != v->pubkey_bytes)) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_ML_KEM_NO_FORMAT,
"no matching enabled %s private key output formats",
v->algorithm_name);
goto end;
}
- len = vp8->p8_bytes;
+ len = p8fmt->p8_bytes;
if (out == NULL) {
ret = len;
if ((pos = buf = OPENSSL_malloc((size_t) len)) == NULL)
goto end;
- if (vp8->p8_magic != 0)
- pos = OPENSSL_store_u32_be(pos, vp8->p8_magic);
- if (vp8->seed_length != 0) {
+ switch (p8fmt->p8_shift) {
+ case 0:
+ pos = OPENSSL_store_u32_be(pos, p8fmt->p8_magic);
+ break;
+ case 2:
+ pos = OPENSSL_store_u16_be(pos, (uint16_t)p8fmt->p8_magic);
+ break;
+ case 4:
+ break;
+ default:
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "error encoding %s private key",
+ v->algorithm_name);
+ goto end;
+ }
+
+ if (p8fmt->seed_length != 0) {
/*
* Either the tag/len were already included in |magic| or they require
* us to write two bytes now.
*/
- if (pos + sizeof(uint16_t) == buf + vp8->seed_offset)
- pos = OPENSSL_store_u16_be(pos, vp8->seed_magic);
- if (pos != buf + vp8->seed_offset
+ if (pos + sizeof(uint16_t) == buf + p8fmt->seed_offset)
+ pos = OPENSSL_store_u16_be(pos, p8fmt->seed_magic);
+ if (pos != buf + p8fmt->seed_offset
|| !ossl_ml_kem_encode_seed(pos, ML_KEM_SEED_BYTES, key)) {
ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
"error encoding %s private key",
}
pos += ML_KEM_SEED_BYTES;
}
- if (vp8->priv_length != 0) {
- if (pos + sizeof(uint32_t) == buf + vp8->priv_offset)
- pos = OPENSSL_store_u32_be(pos, vp8->priv_magic);
- if (pos != buf + vp8->priv_offset
+ if (p8fmt->priv_length != 0) {
+ if (pos + sizeof(uint32_t) == buf + p8fmt->priv_offset)
+ pos = OPENSSL_store_u32_be(pos, p8fmt->priv_magic);
+ if (pos != buf + p8fmt->priv_offset
|| !ossl_ml_kem_encode_private_key(pos, v->prvkey_bytes, key)) {
ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
"error encoding %s private key",
pos += v->prvkey_bytes;
}
/* OQS form output with tacked-on public key */
- if (vp8->pub_length != 0) {
+ if (p8fmt->pub_length != 0) {
/* The OQS pubkey is never separately DER-wrapped */
- if (pos != buf + vp8->pub_offset
+ if (pos != buf + p8fmt->pub_offset
|| !ossl_ml_kem_encode_public_key(pos, v->pubkey_bytes, key)) {
ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
"error encoding %s private key",
}
end:
- OPENSSL_free(vp8_alloc);
+ OPENSSL_free(fmt_slots);
if (ret == 0)
OPENSSL_free(buf);
return ret;
# define ML_KEM_SPKI_OVERHEAD 22
typedef struct {
const uint8_t asn1_prefix[ML_KEM_SPKI_OVERHEAD];
-} ML_KEM_SPKI_INFO;
+} ML_KEM_SPKI_FMT;
/*-
* For each parameter set we support a few PKCS#8 input formats, three
* corresponding to the "either or both" variants of:
*
- * ML-KEM-PrivateKey ::= SEQUENCE {
- * seed OCTET STRING SIZE (64) OPTIONAL,
- * expandedKey [1] IMPLICIT OCTET STRING SIZE (1632 | 2400 | 3172) OPTIONAL }
- * (WITH COMPONENTS {..., seed PRESENT } |
- * WITH COMPONENTS {..., expandedKey PRESENT })
+ * ML-KEM-PrivateKey ::= CHOICE {
+ * seed [0] IMPLICIT OCTET STRING SIZE (64),
+ * expandedKey OCTET STRING SIZE (1632 | 2400 | 3168)
+ * both SEQUENCE {
+ * seed OCTET STRING SIZE (64),
+ * expandedKey OCTET STRING SIZE (1632 | 2400 | 3168) } }
*
- * and two more for historical OQS encodings.
+ * one more for a historical OQS encoding:
*
- * - OQS private key: OCTET STRING
* - OQS private + public key: OCTET STRING
* (The public key is ignored, just as with PKCS#8 v2.)
*
- * An offset of zero means that particular field is absent.
+ * and two more that are the minimal IETF non-ASN.1 seed encoding:
+ *
+ * - Bare seed (just the 32 bytes)
+ * - Bare priv (just the key bytes)
+ *
+ * A length of zero means that particular field is absent.
+ *
+ * The p8_shift is 0 when the top-level tag+length occupy four bytes, 2 when
+ * they occupy two by†es, and 4 when no tag is used at all.
*/
typedef struct {
- const char *p8_name;
- size_t p8_bytes;
- uint32_t p8_magic;
- uint16_t seed_magic;
- size_t seed_offset;
- size_t seed_length;
- uint32_t priv_magic;
- size_t priv_offset;
- size_t priv_length;
- size_t pub_offset;
- size_t pub_length;
-} ML_KEM_PKCS8_INFO;
+ const char *p8_name; /* Format name */
+ size_t p8_bytes; /* Total P8 encoding length */
+ int p8_shift; /* 4 - (top-level tag + len) */
+ uint32_t p8_magic; /* The tag + len value */
+ uint16_t seed_magic; /* Interior tag + len for the seed */
+ size_t seed_offset; /* Seed offset from start */
+ size_t seed_length; /* Seed bytes */
+ uint32_t priv_magic; /* Interior tag + len for the key */
+ size_t priv_offset; /* Key offset from start */
+ size_t priv_length; /* Key bytes */
+ size_t pub_offset; /* Pubkey offset */
+ size_t pub_length; /* Pubkey bytes */
+} ML_KEM_PKCS8_FMT;
typedef struct {
- const ML_KEM_SPKI_INFO *spki_info;
- const ML_KEM_PKCS8_INFO *pkcs8_info;
+ const ML_KEM_SPKI_FMT *spkifmt;
+ const ML_KEM_PKCS8_FMT *p8fmt;
} ML_KEM_CODEC;
typedef struct {
- const ML_KEM_PKCS8_INFO *vp8_entry;
- int vp8_pref;
-} ML_KEM_PKCS8_PREF;
+ const ML_KEM_PKCS8_FMT *fmt;
+ int pref;
+} ML_KEM_PKCS8_FMT_PREF;
__owur
ML_KEM_KEY *ossl_ml_kem_d2i_PUBKEY(const uint8_t *pubenc, int publen,
setup("test_ml_kem_codecs");
my @algs = qw(512 768 1024);
-my @formats = qw(seed-priv priv-only seed-only priv-oqs pair-oqs bare-seed bare-priv);
+my @formats = qw(seed-priv priv-only seed-only oqskeypair bare-seed bare-priv);
plan skip_all => "ML-KEM isn't supported in this build"
if disabled("ml-kem");
my $pub = sprintf("pub-%s.pem", $alg);
my %formats = map { ($_, sprintf("prv-%s-%s.pem", $alg, $_)) } @formats;
- # 31(1 + 5 * 6) tests
+ # (1 + 6 * @formats) tests
my $i = 0;
my $in0 = data_file($pub);
my $der0 = sprintf("pub-%s.%d.der", $alg, $i++);
'-provparam', "ml-kem.input_formats=$rest"])));
}
- # 13(3 + 5 * 2) tests
+ # (3 + 2 * @formats) tests
# Check encap/decap ciphertext and shared secrets
$i = 0;
my $refct = sprintf("ct-%s.dat", $alg);
ok(!compare(data_file($formats{'priv-only'}), $privpref),
sprintf("seed non-preference via provparam key match: %s", $alg));
- # 10(5 * 2) tests
+ # (2 * @formats) tests
# Check text encoding
while (my ($f, $k) = each %formats) {
my $txt = sprintf("prv-%s-%s.txt", $alg,
-----BEGIN PRIVATE KEY-----
-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
+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
+JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
-----END PRIVATE KEY-----
+++ /dev/null
------BEGIN PRIVATE KEY-----
-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
-JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
------END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
-MFYCAQAwCwYJYIZIAWUDBAQDBEQwQgRAAAECAwQFBgcICQoLDA0ODxAREhMUFRYX
-GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
+MFQCAQAwCwYJYIZIAWUDBAQDBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIMvgIBADALBglghkgBZQMEBAMEggyqMIIMpgRAAAECAwQFBgcICQoLDA0ODxAR
-EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P4GC
+EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwSC
DGD3e39rFcc/4sxUa2f7d0yhm0LNRj6p+7mEykd6d7bHEIfL8FGr5HNqkHLG6HDI
MRxVlj9QCjx7G48qWFWPScYlJ7bFlLXnrLO89ZcnOldDUX0VEgi9SqYedbpnsL1Z
SplJGWJ6wKgE1InhcTNrwzn0ZmcG5RNEErNmgj1QMYyL8mGrEgoooE/sAcwV8rcZ
-----BEGIN PRIVATE KEY-----
-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
+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
+JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
-----END PRIVATE KEY-----
+++ /dev/null
------BEGIN PRIVATE KEY-----
-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
-JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
------END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
-MFYCAQAwCwYJYIZIAWUDBAQBBEQwQgRAAAECAwQFBgcICQoLDA0ODxAREhMUFRYX
-GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
+MFQCAQAwCwYJYIZIAWUDBAQBBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIGvgIBADALBglghkgBZQMEBAEEggaqMIIGpgRAAAECAwQFBgcICQoLDA0ODxAR
-EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P4GC
+EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwSC
BmBwVU/UNjRPJ4Wxs7G6wYS2Z5ADM2wm8Vp96HjEglxr4D88SkgPdbdIaq0x06AF
GGI/0gerUo3WJyFJWDWuAGLDZ7dKcbrxCq0OiikCB2vjE0i+sVzMCVfN67Sv8iZ1
a7xgG2Voq3hKy66zRwLw+GomICEYsisj+DVYd2x5wU26mDN5yAPg3MMWChF1cDDm
-----BEGIN PRIVATE KEY-----
-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
+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
+qcDGBzIls0cDpK8Ek4LEdXPaaP3pJFrUROMbH721IfH2Hze8DO8pIGfmcNKKH/2Q
+T28RkKmWkYoTA3psq/PDc7+Cls03qzO6d0aAnMP4reGzY5vVe/zGllCqrx3hmPxM
+BGMpnlLEYXgMxCj8XQSlxRhQy6bCpSdDQGdXk92gm+RMKeY5XGX4XSoKfG30EeaR
+Gx8stsNRzS6HX1G2OL53YJfpPi8rL4PaC+70qoW6nnY6tkUCoMpSIunqtbO3CI7V
+IGDoyCablDpxqwrhxbG2h9LgGc+ANrz5v257rDqqNuQWYPqkVA8mSM2ToYnsXC3q
+cLrKqk/8kG+QgQ6htnvyTyx4z2uogarqYcBlK/+VsbrkQm0Xc7nMLKgsIeOMY247
+HFIyRJhrC+ioP13Vzy1Udi+zxev1m46IUwKxzkcDPt92D04Cm+QLbVZrGd11is1c
+dBKHgTEkT5AXLFPyZmPCHZBTAdSLr5HJF8x3eenYgCzBDYmjcFCZoq06OoiWdDwR
+RGmAk74lfay2bceFIouRLI2WXRSqKDQsOsSpP++lMrIJRd3BAgE5wU1ji5CMTd3p
+oGRblbLkQU1Au3nwRBODDxWoc8KLtwWcJ0EAIBXyBAjwWOcVsL+ZW1OAt90yWgVq
+uX5lmivgzfbDNzHGg6Y0t3HoySoTmu5LsOSccHcyHUL8GZ98HymMpiXSI6XCY6A8
+xIFZt4EmZbeGN+ThhyCywpprmfQnZqTLxNxQi6lLqDuJw6XHj4uya72beb64yBgk
+kPV5PuW5YBO3S34WninRYvExVGTqfXJDbYm3VRYRksgcwt0ci4u6eV70Ju4cwBw3
+qqN7LP+LCjeLR8vQtNSTmM/CcSlZaZ+gvYzYRmasxh9UG4T6lrnIVOTnXpFErdtE
+uFZqV9+7VFzkI8AzRvKywakXgNFSqN4aTUycrN5zksmWiIzCOZwCw4szU634rKso
+OSTaAKBbduc4xyyTDWy6Ca4WiZD6of7yIm54CGHUFu/0AvT3WfxkirH5cQAQkIf5
+bksUjSyzHkgFMU6gzZX7Aj6sDZiUdLpCAde0HSb1OUshfupbNLcaizeTHA5ZQnHg
+t8czJXJAIz57pzVgPkJah97ncHnjfLKKIXZFlM5TUNjaK2KgcXSUMDLsicmICcc7
+ZCPTDB0oOnZqZNiXA8PWKbSXgo1IMgw0YhB5eimKoQ1CPI3aBp0CvFnmzfA6CWuL
+PaTKubgMpKFJB2cszvHsT68jSgvFt+nUc/KzEzs7JqHRdctnp4BZGWmcAvdlMbmc
+X4kYBwS7TKRTXFuJcmecZgoHxeUUuHAJyGLrj1FXaV77P8QKne9rgcHMAqJJrk8J
+StDZvTSFwcHGgIBSCnyMYyAyzuc4FU5cUXbAfaVgJHdqQw/nbqz2ZaP3uDIQIhW8
+gvEJOcg1VwQzao+sHYHkuwSFql18dNa1m75cXpcqDYusQRtVtdVVfNaAoaj3G064
+a8SMmgUJcxpUvZ1ykLJ5Y+Q3Lcmxmc/crAsBrNKKYjlREuTENkjWIsSMgjTQFEDo
+zDdskn8jpa/JrAR0xmInTkJFJchVLs47P+JlFt6QG8fVFb3olVjmJslcgLkzQvgB
+AATznmxslIccXjRMqzlmyDX5qWpZr9McQChrOLHBp4RwurlHUYk0RTzoZzapGfH1
+ptUQqG9UVPw5gMtcdlvSvV97NrFBDWY1yM60fE3aDXaijqyTnHHDAkgEhmxxYmZY
+RCFjwsIhF+UKzvzmN4qYVlIwKk7wws4Mxxa3eW4ray43d9+hrD2iWaMbWptTD4y2
+OKgaYqwwGEmrr5WnMBvaMAaJCb/bfmfbzLs4pVUaJbGjoPaFdIrVdT2IgPABbGJ0
+hhZjhMVXH+I2WQA2TQODEeLYdds2ZoaTK17GAkMKNp6Hpu9cM4eGZXglvUwFes65
+I+sJNeaQXmO0ztf4CFenc91ksVDSZhLqmsEgUtsgF78YQ8y0sygbaQ3HKK36hcAC
+gbjjwJKHM1+Fa0/CiS9povV5Ia2gGRTECYhmLVd2lmKnhjUbm2ZJPat5WU2YbeIQ
+DWW6D/TqWLgVONJKRDWiWPrCVASqf0H2WLE4UGXhWNy2ARVzJyD0BFmqrBXkBpU6
+kKxSmX0czQcAYO/GXbnmUzVEZ/rVbscTyG51QMQjrPJmn1L6b0rGiI2HHvPoR8Ap
+qKr7uS4XskqgebH0GbphdbRCr7EZCdSla3CgM1soc5IYqnyTSOLDwvPrPRWkHmQX
+wN2Uv+shQZsxGnuxOhgLvoMyGKmmsXRHzIXyJYWVh6cwdwSay8/UTQ8CVDjhXRU4
+Jw1Ybhv4MZKpRZz2PA6XL4UpdnmDHs8SFQmFHLg0D28Qew+hoO/Rs2qBibwIXE9c
+t4TlU/QbkY+AOXzhlW94W+43fKmqi+aZitowwmt8PYxrVSVMyWIDsgxCruCsTh67
+QI5JqeP4edCrB4XrcCVCXRMFoimcAV4SDRY7DhlJTOVyU9AkbRgnRcuBl6t0OLPB
+u3lyvsWjBuujVnhVwBRpn+9lrlTHcKDYXBhADPZCrtxmB3e6SxOFAr1aeBL2IfhK
+SClrmN1DIrbxWCi4qPDgCoukSlPDqLFDVxsHQKvVZ9rxzenHnCBLbV4lnRdmoxu7
+y05qBc9FAhdrMBwcL0Ekd1AVe87IXoCbMKTWDXdHzdD1uZqoyCaYdRd5OqqAgKCx
+JKhVjfcrvje3X07btr6CFtbGM/srIoDiURPYaV5DSBw+6zl+sZJQUim2eiAeqJPD
+4ssy2ovDQvpN6gV4ok4W2Pj5ODqVt3BQ9Nn9L1cz7sHWPvPCPr+ZGBc2aacgISIj
+JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
-----END PRIVATE KEY-----
+++ /dev/null
------BEGIN PRIVATE KEY-----
-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
-JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
------END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
-MFYCAQAwCwYJYIZIAWUDBAQCBEQwQgRAAAECAwQFBgcICQoLDA0ODxAREhMUFRYX
-GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw==
+MFQCAQAwCwYJYIZIAWUDBAQCBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIJvgIBADALBglghkgBZQMEBAIEggmqMIIJpgRAAAECAwQFBgcICQoLDA0ODxAR
-EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P4GC
+EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwSC
CWAn0qd/M3VvYSCO8ROr6CWVhz1KvHMOW11nlSm/akzrY4NCcjGoYS9BVQUVrLpS
5I6ti5QoM7vmhl0T0Up50sXD4H8KBW2N56rfyroFjEk8gLN8q4xWJ1O7O6a27IKX
+IXqp1QNUwAVqEQG5VsTZrV34jbOWKJtih61pE1UIyPCFn2b9KR/mFaZygW65DuN