Skip to content

Commit

Permalink
Composite sigs update (#549)
Browse files Browse the repository at this point in the history
* update the composite to draft-ietf-lamps-pq-composite-sigs-02

Signed-off-by: venturf <[email protected]>

* changing the condition on pss salt and mgf1, and raising an error if the right pss is not found

Signed-off-by: feventura <[email protected]>

* Adding Missing Composite documentation

Signed-off-by: feventura <[email protected]>

* adding double octet string encoding to ed25519 and ed448 as rfc8410

Signed-off-by: feventura <[email protected]>

* merge from upstream

Signed-off-by: feventura <[email protected]>

* changes to get_composite_idx

Signed-off-by: feventura <[email protected]>

---------

Signed-off-by: venturf <[email protected]>
Signed-off-by: feventura <[email protected]>
Co-authored-by: venturf <[email protected]>
  • Loading branch information
feventura and venturf authored Oct 31, 2024
1 parent b60daf7 commit 8680f17
Show file tree
Hide file tree
Showing 12 changed files with 369 additions and 212 deletions.
13 changes: 13 additions & 0 deletions ALGORITHMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,23 @@ As standardization for these algorithms within TLS is not done, all TLS code poi
| mldsa44 | 0xfed0 |Yes| OQS_CODEPOINT_MLDSA44
| p256_mldsa44 | 0xfed3 |Yes| OQS_CODEPOINT_P256_MLDSA44
| rsa3072_mldsa44 | 0xfed4 |Yes| OQS_CODEPOINT_RSA3072_MLDSA44
| mldsa44_pss2048 | 0xfee1 |Yes| OQS_CODEPOINT_MLDSA44_pss2048
| mldsa44_rsa2048 | 0xfee2 |Yes| OQS_CODEPOINT_MLDSA44_rsa2048
| mldsa44_ed25519 | 0xfee3 |Yes| OQS_CODEPOINT_MLDSA44_ed25519
| mldsa44_p256 | 0xfee4 |Yes| OQS_CODEPOINT_MLDSA44_p256
| mldsa44_bp256 | 0xfee5 |Yes| OQS_CODEPOINT_MLDSA44_bp256
| mldsa65 | 0xfed1 |Yes| OQS_CODEPOINT_MLDSA65
| p384_mldsa65 | 0xfed5 |Yes| OQS_CODEPOINT_P384_MLDSA65
| mldsa65_pss3072 | 0xfee6 |Yes| OQS_CODEPOINT_MLDSA65_pss3072
| mldsa65_rsa3072 | 0xfee7 |Yes| OQS_CODEPOINT_MLDSA65_rsa3072
| mldsa65_p256 | 0xfee8 |Yes| OQS_CODEPOINT_MLDSA65_p256
| mldsa65_bp256 | 0xfee9 |Yes| OQS_CODEPOINT_MLDSA65_bp256
| mldsa65_ed25519 | 0xfeea |Yes| OQS_CODEPOINT_MLDSA65_ed25519
| mldsa87 | 0xfed2 |Yes| OQS_CODEPOINT_MLDSA87
| p521_mldsa87 | 0xfed6 |Yes| OQS_CODEPOINT_P521_MLDSA87
| mldsa87_p384 | 0xfeeb |Yes| OQS_CODEPOINT_MLDSA87_p384
| mldsa87_bp384 | 0xfeec |Yes| OQS_CODEPOINT_MLDSA87_bp384
| mldsa87_ed448 | 0xfeed |Yes| OQS_CODEPOINT_MLDSA87_ed448
| falcon512 | 0xfed7 |Yes| OQS_CODEPOINT_FALCON512
| p256_falcon512 | 0xfed8 |Yes| OQS_CODEPOINT_P256_FALCON512
| rsa3072_falcon512 | 0xfed9 |Yes| OQS_CODEPOINT_RSA3072_FALCON512
Expand Down
2 changes: 1 addition & 1 deletion STANDARDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ components, this provider implements the following standards:
- Hybrid post-quantum / traditional private keys:
- Simple concatenation of traditional and post-quantum components in plain binary / OCTET_STRING representations.

- For composite signatures, the implementation follows [this IETF draft](https://datatracker.ietf.org/doc/draft-ounsworth-pq-composite-sigs/) (version 13). Note that only those PQ algorithms denoted with the marker "composite" in [oqs-template/generate.yml](oqs-template/generate.yml) are provided with composite variants and not all.
- For composite signatures, the implementation follows [this IETF draft](https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-sigs/) (version 02). Note that only those PQ algorithms denoted with the marker "composite" in [oqs-template/generate.yml](oqs-template/generate.yml) are provided with composite variants and not all.

Note: Please heed the [documentation on the enablement of KEM encoders](CONFIGURE.md#oqs_kem_encoders) via PKCS#8 and X.509.
3 changes: 3 additions & 0 deletions oqs-template/ALGORITHMS.md/ids.fragment
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
{%- for classical_alg in variant['mix_with'] %}
| {{ classical_alg['name'] }}_{{variant['name']}} | {{ classical_alg['code_point'] }} | {%- if variant['enable'] -%} Yes {%- else -%} No {%- endif -%} | OQS_CODEPOINT_{{ classical_alg['name']|upper }}_{{ variant['name']|upper }}
{%- endfor %}
{%- for composite_alg in variant['composite'] %}
| {{variant['name']}}_{{ composite_alg['name'] }} | {{ composite_alg['code_point'] }} | {%- if variant['enable'] -%} Yes {%- else -%} No {%- endif -%} | OQS_CODEPOINT_{{ variant['name']|upper }}_{{ composite_alg['name'] }}
{%- endfor %}
{%- endfor %}
{%- endfor %}

7 changes: 7 additions & 0 deletions oqs-template/generate_oid_nid_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ def gen_sig_table(oqslibdocdir):
claimed_nist_level,
hybrid['code_point'],
hybrid['oid']])
for composite in variant['composite']:
table.append([variant['name'] + ' **composite with** ' + composite['name'],
liboqs_sigs[sig['family']]['spec-version'],
str(liboqs_sigs[sig['family']]['nist-round']),
claimed_nist_level,
composite['code_point'],
composite['oid']])
except KeyError as ke:
# Non-existant NIDs mean this alg is not supported any more
pass
Expand Down
371 changes: 192 additions & 179 deletions oqs-template/oqs-sig-info.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@


/** \brief List of composite signature algorithms. */
const char *kCompositeSignatureAlgorithms[] = {
{% for sig in config['sigs'] %}
{%- for variant in sig['variants'] %}
{%- for composite_alg in variant['composite'] -%}
"{{variant['name']}}_{{ composite_alg['name'] }}",
{%- endfor -%}
{%- endfor %}
{%- endfor %}
NULL,
};

121 changes: 97 additions & 24 deletions oqsprov/oqs_encode_key2any.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,9 @@ static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder) {
OPENSSL_malloc(oqsxkey->numkeys * sizeof(ASN1_OCTET_STRING *));
unsigned char **temp =
OPENSSL_malloc(oqsxkey->numkeys * sizeof(unsigned char *));
size_t *templen = OPENSSL_malloc(oqsxkey->numkeys * sizeof(size_t));
unsigned char *ed_internal;
size_t *templen = OPENSSL_malloc(oqsxkey->numkeys * sizeof(size_t)),
ed_internallen;
PKCS8_PRIV_KEY_INFO *p8inf_internal = NULL;
sk = sk_ASN1_TYPE_new_null();
int i;
Expand Down Expand Up @@ -789,7 +791,7 @@ static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder) {
memcpy(buf, oqsxkey->comp_privkey[i],
buflen); // buflen for classical (RSA)
// might be different from
// oqsxkey->privkeylen_cmp[
// oqsxkey->privkeylen_cmp
}

if (nid == EVP_PKEY_EC) { // add the curve OID with the ECPubkey OID
Expand All @@ -800,30 +802,87 @@ static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder) {
version = V_ASN1_UNDEF;
pval = NULL;
}
if (!PKCS8_pkey_set0(p8inf_internal, OBJ_nid2obj(nid), 0, version,
pval, buf, buflen)) {
for (int j = 0; j <= i; j++) {
OPENSSL_cleanse(aString[j]->data, aString[j]->length);
ASN1_OCTET_STRING_free(aString[j]);
OPENSSL_cleanse(aType[j]->value.sequence->data,
aType[j]->value.sequence->length);
OPENSSL_clear_free(temp[j], templen[j]);
if (nid == EVP_PKEY_ED25519 || nid == EVP_PKEY_ED448) {
oct.data = buf;
oct.length = buflen;
oct.flags = 0;
ed_internal = NULL;

ed_internallen = i2d_ASN1_OCTET_STRING(&oct, &ed_internal);
if (ed_internallen < 0) {
for (int j = 0; j <= i; j++) {
OPENSSL_cleanse(aString[j]->data, aString[j]->length);
ASN1_OCTET_STRING_free(aString[j]);
OPENSSL_cleanse(aType[j]->value.sequence->data,
aType[j]->value.sequence->length);
OPENSSL_clear_free(temp[j], templen[j]);
}

sk_ASN1_TYPE_pop_free(sk, &ASN1_TYPE_free);
OPENSSL_free(name);
OPENSSL_free(aType);
OPENSSL_free(aString);
OPENSSL_free(temp);
OPENSSL_free(templen);
OPENSSL_cleanse(buf,
buflen); // buf is part of p8inf_internal so
// we cant free now, we cleanse it
// to remove pkey from memory
PKCS8_PRIV_KEY_INFO_free(
p8inf_internal); // this also free buf
return -1;
}

sk_ASN1_TYPE_pop_free(sk, &ASN1_TYPE_free);
OPENSSL_free(name);
OPENSSL_free(aType);
OPENSSL_free(aString);
OPENSSL_free(temp);
OPENSSL_free(templen);
OPENSSL_cleanse(buf,
buflen); // buf is part of p8inf_internal so we
// cant free now, we cleanse it to
// remove pkey from memory
PKCS8_PRIV_KEY_INFO_free(p8inf_internal); // this also free buf
return -1;
}
if (!PKCS8_pkey_set0(p8inf_internal, OBJ_nid2obj(nid), 0,
version, pval, ed_internal,
ed_internallen)) {
for (int j = 0; j <= i; j++) {
OPENSSL_cleanse(aString[j]->data, aString[j]->length);
ASN1_OCTET_STRING_free(aString[j]);
OPENSSL_cleanse(aType[j]->value.sequence->data,
aType[j]->value.sequence->length);
OPENSSL_clear_free(temp[j], templen[j]);
}

sk_ASN1_TYPE_pop_free(sk, &ASN1_TYPE_free);
OPENSSL_free(name);
OPENSSL_free(aType);
OPENSSL_free(aString);
OPENSSL_free(temp);
OPENSSL_free(templen);
OPENSSL_secure_clear_free(buf, buflen);
OPENSSL_cleanse(ed_internal, ed_internallen);
PKCS8_PRIV_KEY_INFO_free(
p8inf_internal); // this also free ed_internal
return -1;
}

} else {
if (!PKCS8_pkey_set0(p8inf_internal, OBJ_nid2obj(nid), 0,
version, pval, buf, buflen)) {
for (int j = 0; j <= i; j++) {
OPENSSL_cleanse(aString[j]->data, aString[j]->length);
ASN1_OCTET_STRING_free(aString[j]);
OPENSSL_cleanse(aType[j]->value.sequence->data,
aType[j]->value.sequence->length);
OPENSSL_clear_free(temp[j], templen[j]);
}

sk_ASN1_TYPE_pop_free(sk, &ASN1_TYPE_free);
OPENSSL_free(name);
OPENSSL_free(aType);
OPENSSL_free(aString);
OPENSSL_free(temp);
OPENSSL_free(templen);
OPENSSL_cleanse(buf,
buflen); // buf is part of p8inf_internal so
// we cant free now, we cleanse it
// to remove pkey from memory
PKCS8_PRIV_KEY_INFO_free(
p8inf_internal); // this also free buf
return -1;
}
}
templen[i] =
i2d_PKCS8_PRIV_KEY_INFO(p8inf_internal,
&temp[i]); // create the privkey info
Expand Down Expand Up @@ -853,12 +912,26 @@ static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder) {
buflen); // buf is part of p8inf_internal so we
// cant free now, we cleanse it to
// remove pkey from memory
PKCS8_PRIV_KEY_INFO_free(p8inf_internal); // this also free buf
if (nid == EVP_PKEY_ED25519 || nid == EVP_PKEY_ED448) {
OPENSSL_cleanse(ed_internal, ed_internallen);
OPENSSL_secure_free(
buf); // in this case the ed_internal is
// freed from the pkcs8_free instead
// of buf, so we need to free buf here
}
PKCS8_PRIV_KEY_INFO_free(
p8inf_internal); // this also free buf or ed_internal
return -1;
}
OPENSSL_free(name);

OPENSSL_cleanse(buf, buflen);
if (nid == EVP_PKEY_ED25519 || nid == EVP_PKEY_ED448) {
OPENSSL_cleanse(ed_internal, ed_internallen);
OPENSSL_secure_free(buf); // in this case the ed_internal is
// freed from the pkcs8_free instead
// of buf, so we need to free buf here
}
PKCS8_PRIV_KEY_INFO_free(p8inf_internal);
}
keybloblen = i2d_ASN1_SEQUENCE_ANY(sk, pder);
Expand Down
2 changes: 1 addition & 1 deletion oqsprov/oqs_prov.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ char *get_oqsname_fromtls(char *tlsname);
char *get_oqsname(int nid);
char *get_cmpname(int nid, int index);
int get_oqsalg_idx(int nid);
int get_composite_idx(int idx);
int get_composite_idx(char *name);

/* Workaround for not functioning EC PARAM initialization
* TBD, check https://github.com/openssl/openssl/issues/16989
Expand Down
4 changes: 2 additions & 2 deletions oqsprov/oqs_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen,
unsigned char *buf;
int i;
int nid = OBJ_sn2nid(oqsxkey->tls_name);
int comp_idx = get_composite_idx(get_oqsalg_idx(nid));
int comp_idx = get_composite_idx(oqsxkey->tls_name);
if (comp_idx == -1)
goto endsign;
const unsigned char *oid_prefix = composite_OID_prefix[comp_idx - 1];
Expand Down Expand Up @@ -799,7 +799,7 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig,
CompositeSignature *compsig;
int i;
int nid = OBJ_sn2nid(oqsxkey->tls_name);
int comp_idx = get_composite_idx(get_oqsalg_idx(nid));
int comp_idx = get_composite_idx(oqsxkey->tls_name);
if (comp_idx == -1)
goto endverify;
unsigned char *buf;
Expand Down
17 changes: 12 additions & 5 deletions oqsprov/oqsprov.c
Original file line number Diff line number Diff line change
Expand Up @@ -997,13 +997,20 @@ static const OSSL_ALGORITHM oqsprovider_decoder[] = {
};

// get the last number on the composite OID
int get_composite_idx(int idx) {
char *s;
int get_composite_idx(char *name) {
char *s = NULL;
int i, len, ret = -1, count = 0;

if (2 * idx > OQS_OID_CNT)
return 0;
s = (char *)oqs_oid_alg_list[idx * 2];
for (i = 1; i <= OQS_OID_CNT; i += 2) {
if (!strcmp((char *)oqs_oid_alg_list[i], name)) {
s = (char *)oqs_oid_alg_list[i - 1];
break;
}
}
if (s == NULL) {
return ret;
}

len = strlen(s);

for (i = 0; i < len; i++) {
Expand Down
13 changes: 13 additions & 0 deletions oqsprov/oqsprov_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,19 @@ OQSX_KEY *oqsx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf,
key_diff = nids_sig[6].length_private_key - buflen;
}

// removing extra OTECT STRING from ED25519 and ED448 keys
if ((keytype == EVP_PKEY_ED25519) ||
(keytype == EVP_PKEY_ED448)) {
ASN1_OCTET_STRING *ed_octet = NULL;
ed_octet = d2i_ASN1_OCTET_STRING(&ed_octet, &buf, buflen);
aux += ed_octet->length;
memcpy(concat_key + plen - 1 - aux, ed_octet->data,
ed_octet->length);
nid = 1; // setting to non zero value so the key is not
// copied again
ASN1_OCTET_STRING_free(ed_octet);
}

if (!nid) {
aux += buflen;
memcpy(concat_key + plen - 1 - aux, buf,
Expand Down
14 changes: 14 additions & 0 deletions test/oqs_test_evp_pkey_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ const char *kHybridSignatureAlgorithms[] = {
};
///// OQS_TEMPLATE_FRAGMENT_HYBRID_SIG_ALGS_END

///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_START

/** \brief List of composite signature algorithms. */
const char *kCompositeSignatureAlgorithms[] = {
"mldsa44_pss2048", "mldsa44_rsa2048",
"mldsa44_ed25519", "mldsa44_p256",
"mldsa44_bp256", "mldsa65_pss3072",
"mldsa65_rsa3072", "mldsa65_p256",
"mldsa65_bp256", "mldsa65_ed25519",
"mldsa87_p384", "mldsa87_bp384",
"mldsa87_ed448", NULL,
};
///// OQS_TEMPLATE_FRAGMENT_COMPOSITE_SIG_ALGS_END

///// OQS_TEMPLATE_FRAGMENT_HYBRID_KEM_ALGS_START

/** \brief List of hybrid KEMs. */
Expand Down

0 comments on commit 8680f17

Please sign in to comment.