Skip to content

Commit e25a143

Browse files
committed
Add support for RSA-PSS keys
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent e4d5e49 commit e25a143

17 files changed

+441
-152
lines changed

src/headers/tomcrypt_custom.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@
605605
/* Maximum recursion limit when processing nested ASN.1 types. */
606606
#define LTC_DER_MAX_RECURSION 30
607607
#endif
608+
#ifndef LTC_DER_OID_DEFAULT_NODES
609+
/* Default number of nodes when decoding an OID. */
610+
#define LTC_DER_OID_DEFAULT_NODES 12
611+
#endif
608612
#endif
609613

610614
#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_SSH)

src/headers/tomcrypt_pk.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ enum ltc_pka_id {
4040
LTC_PKA_X25519,
4141
LTC_PKA_ED25519,
4242
LTC_PKA_DH,
43+
LTC_PKA_RSA_PSS,
4344
LTC_PKA_NUM
4445
};
4546

@@ -62,7 +63,18 @@ int rand_prime(void *N, long len, prng_state *prng, int wprng);
6263
/* ---- RSA ---- */
6364
#ifdef LTC_MRSA
6465

65-
/** RSA PKCS style key */
66+
typedef struct ltc_rsa_parameters {
67+
/** PSS/OAEP or PKCS #1 v1.5 style
68+
* 0 -> PKCS #1 v1.5, 1 -> PSS/OAEP */
69+
int pss_oaep;
70+
/** saltLength is only defined for PSS
71+
* If saltLength == 0 -> OAEP, else -> PSS */
72+
unsigned long saltlen;
73+
/** hash and MGF hash algorithms */
74+
const char *hash_alg, *mgf1_hash_alg;
75+
} ltc_rsa_parameters;
76+
77+
/** RSA key */
6678
typedef struct Rsa_key {
6779
/** Type of key, PK_PRIVATE or PK_PUBLIC */
6880
int type;
@@ -82,6 +94,8 @@ typedef struct Rsa_key {
8294
void *dP;
8395
/** The d mod (q - 1) CRT param */
8496
void *dQ;
97+
/** Further parameters of the RSA key */
98+
ltc_rsa_parameters params;
8599
} rsa_key;
86100

87101
int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);

src/headers/tomcrypt_private.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ enum ltc_oid_id {
6060
LTC_OID_X25519,
6161
LTC_OID_ED25519,
6262
LTC_OID_DH,
63+
LTC_OID_RSA_OAEP,
64+
LTC_OID_RSA_MGF1,
65+
LTC_OID_RSA_PSS,
6366
LTC_OID_NUM
6467
};
6568

@@ -443,8 +446,14 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long
443446

444447
/* ---- DH Routines ---- */
445448
#ifdef LTC_MRSA
449+
typedef enum ltc_rsa_op {
450+
LTC_RSA_CRYPT,
451+
LTC_RSA_SIGN
452+
} ltc_rsa_op;
446453
int rsa_init(rsa_key *key);
447454
void rsa_shrink_key(rsa_key *key);
455+
int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx);
456+
int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b);
448457
int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e,
449458
rsa_key *key); /* used by op-tee */
450459
int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key);
@@ -730,7 +739,11 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo
730739
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
731740
ltc_asn1_list* parameters, unsigned long *parameters_len,
732741
public_key_decode_cb callback, void *ctx);
733-
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki);
742+
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki);
743+
int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen,
744+
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
745+
ltc_asn1_list* parameters, unsigned long *parameters_len,
746+
public_key_decode_cb callback, void *ctx);
734747

735748
/* SUBJECT PUBLIC KEY INFO */
736749
int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
@@ -741,7 +754,7 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
741754
enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
742755
ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
743756

744-
int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka);
757+
int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka);
745758
int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root);
746759

747760
int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);

src/misc/crypt/crypt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ const char *crypt_build_settings =
458458
#if defined(LTC_DER)
459459
" DER "
460460
" " NAME_VALUE(LTC_DER_MAX_RECURSION) " "
461+
" " NAME_VALUE(LTC_DER_OID_DEFAULT_NODES) " "
461462
#endif
462463
#if defined(LTC_PKCS_1)
463464
" PKCS#1 "

src/pk/asn1/oid/pk_get.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
typedef struct {
88
enum ltc_oid_id id;
99
enum ltc_pka_id pka;
10-
const char* oid;
10+
const char *hash;
11+
const char *oid;
1112
} oid_table_entry;
1213

1314
static const oid_table_entry pka_oids[] = {
14-
{ LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL },
15-
{ LTC_OID_RSA, LTC_PKA_RSA, "1.2.840.113549.1.1.1" },
16-
{ LTC_OID_DSA, LTC_PKA_DSA, "1.2.840.10040.4.1" },
17-
{ LTC_OID_EC, LTC_PKA_EC, "1.2.840.10045.2.1" },
18-
{ LTC_OID_EC_PRIMEF, LTC_PKA_EC, "1.2.840.10045.1.1" },
19-
{ LTC_OID_X25519, LTC_PKA_X25519, "1.3.101.110" },
20-
{ LTC_OID_ED25519, LTC_PKA_ED25519, "1.3.101.112" },
21-
{ LTC_OID_DH, LTC_PKA_DH, "1.2.840.113549.1.3.1" },
15+
{ LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL, NULL },
16+
{ LTC_OID_RSA, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.1" },
17+
{ LTC_OID_DSA, LTC_PKA_DSA, NULL, "1.2.840.10040.4.1" },
18+
{ LTC_OID_EC, LTC_PKA_EC, NULL, "1.2.840.10045.2.1" },
19+
{ LTC_OID_EC_PRIMEF, LTC_PKA_EC, NULL, "1.2.840.10045.1.1" },
20+
{ LTC_OID_X25519, LTC_PKA_X25519, NULL, "1.3.101.110" },
21+
{ LTC_OID_ED25519, LTC_PKA_ED25519, NULL, "1.3.101.112" },
22+
{ LTC_OID_DH, LTC_PKA_DH, NULL, "1.2.840.113549.1.3.1" },
23+
{ LTC_OID_RSA_OAEP, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.7" },
24+
{ LTC_OID_RSA_MGF1, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.8" },
25+
{ LTC_OID_RSA_PSS, LTC_PKA_RSA_PSS, NULL, "1.2.840.113549.1.1.10" },
2226
};
2327

2428
static LTC_INLINE const oid_table_entry* s_get_entry(enum ltc_oid_id id)
@@ -43,21 +47,35 @@ int pk_get_oid(enum ltc_oid_id id, const char **st)
4347
return CRYPT_INVALID_ARG;
4448
}
4549

46-
/*
47-
Returns the PKA ID requested.
48-
@return CRYPT_OK if valid
49-
*/
50-
int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka)
50+
static LTC_INLINE int s_get_values(enum ltc_oid_id id, enum ltc_pka_id *pka, const char **hash)
5151
{
5252
const oid_table_entry* e = s_get_entry(id);
5353
LTC_ARGCHK(pka != NULL);
5454
if (e != NULL) {
5555
*pka = e->pka;
56+
if (hash) {
57+
*hash = e->hash;
58+
} else if (e->hash) {
59+
/* If we don't want the hash result, but the entry has a hash, we're most likely
60+
* confused and we prefer to stop processing then, instead of continuing with a
61+
* maybe wrong assumption.
62+
*/
63+
return CRYPT_INVALID_ARG;
64+
}
5665
return CRYPT_OK;
5766
}
5867
return CRYPT_INVALID_ARG;
5968
}
6069

70+
/*
71+
Returns the PKA ID requested.
72+
@return CRYPT_OK if valid
73+
*/
74+
int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka)
75+
{
76+
return s_get_values(id, pka, NULL);
77+
}
78+
6179
/*
6280
Returns the OID ID requested.
6381
@return CRYPT_OK if valid

src/pk/asn1/x509/x509_decode_public_key_from_certificate.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#ifdef LTC_DER
1111

1212
/**
13-
Try to decode the public key from a X.509 certificate
13+
Process the public key from the SubjectPublicKeyInfo of a X.509 certificate
1414
@param in The input buffer
1515
@param inlen The length of the input buffer
1616
@param algorithm One out of the enum #public_key_algorithms
@@ -19,53 +19,82 @@
1919
@param parameters_len [in/out] The number of parameters to include
2020
@param callback The callback
2121
@param ctx The context passed to the callback
22-
@return CRYPT_OK on success,
23-
CRYPT_NOP if no SubjectPublicKeyInfo was found,
24-
another error if decoding or memory allocation failed
22+
@return CRYPT_OK on success
2523
*/
26-
int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen,
27-
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
28-
ltc_asn1_list* parameters, unsigned long *parameters_len,
29-
public_key_decode_cb callback, void *ctx)
24+
int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen,
25+
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
26+
ltc_asn1_list* parameters, unsigned long *parameters_len,
27+
public_key_decode_cb callback, void *ctx)
3028
{
3129
int err;
3230
unsigned char *tmpbuf = NULL;
3331
unsigned long tmpbuf_len;
34-
ltc_asn1_list *decoded_list = NULL, *spki;
35-
36-
LTC_ARGCHK(in != NULL);
37-
LTC_ARGCHK(inlen != 0);
38-
LTC_ARGCHK(callback != NULL);
3932

40-
if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) {
41-
return err;
42-
}
33+
LTC_ARGCHK(in != NULL);
34+
LTC_ARGCHK(callback != NULL);
4335

4436
if (algorithm == LTC_OID_EC) {
45-
err = callback(spki->data, spki->size, ctx);
37+
err = callback(in, inlen, ctx);
4638
} else {
4739

4840
tmpbuf_len = inlen;
4941
tmpbuf = XCALLOC(1, tmpbuf_len);
5042
if (tmpbuf == NULL) {
51-
err = CRYPT_MEM;
52-
goto LBL_OUT;
43+
return CRYPT_MEM;
5344
}
5445

55-
err = x509_decode_subject_public_key_info(spki->data, spki->size,
46+
err = x509_decode_subject_public_key_info(in, inlen,
5647
algorithm, tmpbuf, &tmpbuf_len,
5748
param_type, parameters, parameters_len);
5849
if (err == CRYPT_OK) {
5950
err = callback(tmpbuf, tmpbuf_len, ctx);
60-
goto LBL_OUT;
6151
}
6252
}
6353

64-
LBL_OUT:
65-
if (decoded_list) der_free_sequence_flexi(decoded_list);
6654
if (tmpbuf != NULL) XFREE(tmpbuf);
6755

6856
return err;
6957
}
7058

59+
/**
60+
Try to decode the public key from a X.509 certificate
61+
@param in The input buffer
62+
@param inlen The length of the input buffer
63+
@param algorithm One out of the enum #public_key_algorithms
64+
@param param_type The parameters' type out of the enum ltc_asn1_type
65+
@param parameters The parameters to include
66+
@param parameters_len [in/out] The number of parameters to include
67+
@param callback The callback
68+
@param ctx The context passed to the callback
69+
@return CRYPT_OK on success,
70+
CRYPT_NOP if no SubjectPublicKeyInfo was found,
71+
another error if decoding or memory allocation failed
72+
*/
73+
int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen,
74+
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
75+
ltc_asn1_list* parameters, unsigned long *parameters_len,
76+
public_key_decode_cb callback, void *ctx)
77+
{
78+
int err;
79+
ltc_asn1_list *decoded_list;
80+
const ltc_asn1_list *spki;
81+
82+
LTC_ARGCHK(in != NULL);
83+
LTC_ARGCHK(inlen != 0);
84+
LTC_ARGCHK(callback != NULL);
85+
86+
if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) {
87+
return err;
88+
}
89+
90+
err = x509_process_public_key_from_spki(spki->data, spki->size,
91+
algorithm, param_type,
92+
parameters, parameters_len,
93+
callback, ctx);
94+
95+
if (decoded_list) der_free_sequence_flexi(decoded_list);
96+
97+
return err;
98+
}
99+
71100
#endif

src/pk/asn1/x509/x509_decode_spki.c

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626
@param spki [out] A pointer to the SubjectPublicKeyInfo
2727
@return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found, another error if decoding failed
2828
*/
29-
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki)
29+
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki)
3030
{
3131
int err;
32-
unsigned long tmp_inlen;
32+
unsigned long tmp_inlen, n, element_is_spki;
3333
ltc_asn1_list *decoded_list = NULL, *l;
3434

3535
LTC_ARGCHK(in != NULL);
@@ -49,29 +49,49 @@ int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list
4949
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
5050
l = l->child;
5151
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
52+
/* TBSCertificate ::= SEQUENCE {
53+
* version [0] EXPLICIT Version DEFAULT v1,
54+
* serialNumber CertificateSerialNumber,
55+
* signature AlgorithmIdentifier,
56+
* issuer Name,
57+
* validity Validity,
58+
* subject Name,
59+
* subjectPublicKeyInfo SubjectPublicKeyInfo,
60+
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
61+
* -- If present, version MUST be v2 or v3
62+
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
63+
* -- If present, version MUST be v2 or v3
64+
* extensions [3] EXPLICIT Extensions OPTIONAL
65+
* -- If present, version MUST be v3
66+
* }
67+
*/
5268
l = l->child;
5369

54-
/* Move forward in the tree until we find this combination
55-
...
56-
SEQUENCE
57-
SEQUENCE
58-
OBJECT IDENTIFIER <some PKA OID, e.g. 1.2.840.113549.1.1.1>
59-
NULL
60-
BIT STRING
70+
/* `l` points now either to 'version' or 'serialNumber', depending on
71+
* whether 'version' is included or defaults to 'v1'.
72+
* 'version' is represented as a LTC_ASN1_CUSTOM_TYPE
73+
* 'serialNumber' is represented as an LTC_ASN1_INTEGER
74+
* Decide now whether to move 5 or 6 elements forward until
75+
* `l` should point to subjectPublicKeyInfo.
6176
*/
62-
do {
63-
/* The additional check for l->data is there to make sure
64-
* we won't try to decode a list that has been 'shrunk'
65-
*/
66-
if ((l->type == LTC_ASN1_SEQUENCE)
67-
&& (l->data != NULL)
68-
&& LOOKS_LIKE_SPKI(l->child)) {
69-
*out = decoded_list;
70-
*spki = l;
71-
return CRYPT_OK;
72-
}
77+
if (l->type == LTC_ASN1_CUSTOM_TYPE)
78+
element_is_spki = 6;
79+
else
80+
element_is_spki = 5;
81+
for (n = 0; n < element_is_spki && l; ++n) {
7382
l = l->next;
74-
} while(l);
83+
}
84+
/* The additional check for l->data is there to make sure
85+
* we won't try to decode a list that has been 'shrunk'
86+
*/
87+
if ((l != NULL)
88+
&& (l->type == LTC_ASN1_SEQUENCE)
89+
&& (l->data != NULL)
90+
&& LOOKS_LIKE_SPKI(l->child)) {
91+
*out = decoded_list;
92+
*spki = l;
93+
return CRYPT_OK;
94+
}
7595
}
7696
}
7797
}

src/pk/asn1/x509/x509_get_pka.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99

1010
#ifdef LTC_DER
1111

12-
int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka)
12+
int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka)
1313
{
1414
der_flexi_check flexi_should[4];
1515
ltc_asn1_list *seqid, *id = NULL;
1616
enum ltc_oid_id oid_id;
1717
int err;
1818
unsigned long n = 0;
1919
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid);
20-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
20+
LTC_SET_DER_FLEXI_CHECK_OPT(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
2121
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
2222
if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) {
2323
return err;

0 commit comments

Comments
 (0)