1 /* 2 * Copyright 2025 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 10 #ifndef PROV_ML_COMMON_CODECS_H 11 # define PROV_ML_COMMON_CODECS_H 12 # pragma once 13 14 # include <openssl/e_os2.h> 15 # include "crypto/ml_dsa.h" 16 # include "prov/provider_ctx.h" 17 18 /*- 19 * The DER ASN.1 encoding of ML-DSA and ML-KEM public keys prepends 22 bytes 20 * to the encoded public key: 21 * 22 * - 4 byte outer sequence tag and length 23 * - 2 byte algorithm sequence tag and length 24 * - 2 byte algorithm OID tag and length 25 * - 9 byte algorithm OID (from NIST CSOR OID arc) 26 * - 4 byte bit string tag and length 27 * - 1 bitstring lead byte 28 */ 29 # define ML_COMMON_SPKI_OVERHEAD 22 30 typedef struct { 31 const uint8_t asn1_prefix[ML_COMMON_SPKI_OVERHEAD]; 32 } ML_COMMON_SPKI_FMT; 33 34 /*- 35 * For each parameter set we support a few PKCS#8 input formats, three 36 * corresponding to the "either or both" variants of: 37 * 38 * ML-DSA-PrivateKey ::= CHOICE { 39 * seed [0] IMPLICIT OCTET STRING (SIZE (32)), 40 * expandedKey OCTET STRING (SIZE (2560 | 4032 | 4896)), 41 * both SEQUENCE { 42 * seed OCTET STRING (SIZE (32)), 43 * expandedKey OCTET STRING (SIZE (2560 | 4032 | 4896)) } } 44 * 45 * ML-KEM-PrivateKey ::= CHOICE { 46 * seed [0] IMPLICIT OCTET STRING (SIZE (64)), 47 * expandedKey OCTET STRING (SIZE (1632 | 2400 | 3168)), 48 * both SEQUENCE { 49 * seed OCTET STRING (SIZE (64)), 50 * expandedKey OCTET STRING SIZE ((1632 | 2400 | 3168)) } } 51 * 52 * one more for a historical OQS encoding: 53 * 54 * - OQS private + public key: OCTET STRING 55 * (The public key is ignored, just as with PKCS#8 v2.) 56 * 57 * and two more that are the minimal IETF non-ASN.1 seed encoding: 58 * 59 * - Bare seed (just the 32 or 64 bytes) 60 * - Bare priv (just the key bytes) 61 * 62 * A length of zero means that particular field is absent. 63 * 64 * The p8_shift is 0 when the top-level tag+length occupy four bytes, 2 when 65 * they occupy two by†es, and 4 when no tag is used at all. 66 */ 67 #define NUM_PKCS8_FORMATS 6 68 69 typedef struct { 70 const char *p8_name; /* Format name */ 71 size_t p8_bytes; /* Total P8 encoding length */ 72 int p8_shift; /* 4 - (top-level tag + len) */ 73 uint32_t p8_magic; /* The tag + len value */ 74 uint16_t seed_magic; /* Interior tag + len for the seed */ 75 size_t seed_offset; /* Seed offset from start */ 76 size_t seed_length; /* Seed bytes */ 77 uint32_t priv_magic; /* Interior tag + len for the key */ 78 size_t priv_offset; /* Key offset from start */ 79 size_t priv_length; /* Key bytes */ 80 size_t pub_offset; /* Pubkey offset */ 81 size_t pub_length; /* Pubkey bytes */ 82 } ML_COMMON_PKCS8_FMT; 83 84 typedef struct { 85 const ML_COMMON_SPKI_FMT *spkifmt; 86 const ML_COMMON_PKCS8_FMT *p8fmt; 87 } ML_COMMON_CODEC; 88 89 typedef struct { 90 const ML_COMMON_PKCS8_FMT *fmt; 91 int pref; 92 } ML_COMMON_PKCS8_FMT_PREF; 93 94 ML_COMMON_PKCS8_FMT_PREF * 95 ossl_ml_common_pkcs8_fmt_order(const char *algorithm_name, 96 const ML_COMMON_PKCS8_FMT *p8fmt, 97 const char *direction, const char *formats); 98 #endif 99