1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <assert.h>
11e1051a39Sopenharmony_ci#include <openssl/cms.h>
12e1051a39Sopenharmony_ci#include <openssl/err.h>
13e1051a39Sopenharmony_ci#include <openssl/core_names.h>
14e1051a39Sopenharmony_ci#include "crypto/asn1.h"
15e1051a39Sopenharmony_ci#include "crypto/rsa.h"
16e1051a39Sopenharmony_ci#include "cms_local.h"
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_cistatic RSA_OAEP_PARAMS *rsa_oaep_decode(const X509_ALGOR *alg)
19e1051a39Sopenharmony_ci{
20e1051a39Sopenharmony_ci    RSA_OAEP_PARAMS *oaep;
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci    oaep = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(RSA_OAEP_PARAMS),
23e1051a39Sopenharmony_ci                                     alg->parameter);
24e1051a39Sopenharmony_ci
25e1051a39Sopenharmony_ci    if (oaep == NULL)
26e1051a39Sopenharmony_ci        return NULL;
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ci    if (oaep->maskGenFunc != NULL) {
29e1051a39Sopenharmony_ci        oaep->maskHash = ossl_x509_algor_mgf1_decode(oaep->maskGenFunc);
30e1051a39Sopenharmony_ci        if (oaep->maskHash == NULL) {
31e1051a39Sopenharmony_ci            RSA_OAEP_PARAMS_free(oaep);
32e1051a39Sopenharmony_ci            return NULL;
33e1051a39Sopenharmony_ci        }
34e1051a39Sopenharmony_ci    }
35e1051a39Sopenharmony_ci    return oaep;
36e1051a39Sopenharmony_ci}
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_cistatic int rsa_cms_decrypt(CMS_RecipientInfo *ri)
39e1051a39Sopenharmony_ci{
40e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pkctx;
41e1051a39Sopenharmony_ci    X509_ALGOR *cmsalg;
42e1051a39Sopenharmony_ci    int nid;
43e1051a39Sopenharmony_ci    int rv = -1;
44e1051a39Sopenharmony_ci    unsigned char *label = NULL;
45e1051a39Sopenharmony_ci    int labellen = 0;
46e1051a39Sopenharmony_ci    const EVP_MD *mgf1md = NULL, *md = NULL;
47e1051a39Sopenharmony_ci    RSA_OAEP_PARAMS *oaep;
48e1051a39Sopenharmony_ci
49e1051a39Sopenharmony_ci    pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
50e1051a39Sopenharmony_ci    if (pkctx == NULL)
51e1051a39Sopenharmony_ci        return 0;
52e1051a39Sopenharmony_ci    if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
53e1051a39Sopenharmony_ci        return -1;
54e1051a39Sopenharmony_ci    nid = OBJ_obj2nid(cmsalg->algorithm);
55e1051a39Sopenharmony_ci    if (nid == NID_rsaEncryption)
56e1051a39Sopenharmony_ci        return 1;
57e1051a39Sopenharmony_ci    if (nid != NID_rsaesOaep) {
58e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE);
59e1051a39Sopenharmony_ci        return -1;
60e1051a39Sopenharmony_ci    }
61e1051a39Sopenharmony_ci    /* Decode OAEP parameters */
62e1051a39Sopenharmony_ci    oaep = rsa_oaep_decode(cmsalg);
63e1051a39Sopenharmony_ci
64e1051a39Sopenharmony_ci    if (oaep == NULL) {
65e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS);
66e1051a39Sopenharmony_ci        goto err;
67e1051a39Sopenharmony_ci    }
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci    mgf1md = ossl_x509_algor_get_md(oaep->maskHash);
70e1051a39Sopenharmony_ci    if (mgf1md == NULL)
71e1051a39Sopenharmony_ci        goto err;
72e1051a39Sopenharmony_ci    md = ossl_x509_algor_get_md(oaep->hashFunc);
73e1051a39Sopenharmony_ci    if (md == NULL)
74e1051a39Sopenharmony_ci        goto err;
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_ci    if (oaep->pSourceFunc != NULL) {
77e1051a39Sopenharmony_ci        X509_ALGOR *plab = oaep->pSourceFunc;
78e1051a39Sopenharmony_ci
79e1051a39Sopenharmony_ci        if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) {
80e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE);
81e1051a39Sopenharmony_ci            goto err;
82e1051a39Sopenharmony_ci        }
83e1051a39Sopenharmony_ci        if (plab->parameter->type != V_ASN1_OCTET_STRING) {
84e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CMS, CMS_R_INVALID_LABEL);
85e1051a39Sopenharmony_ci            goto err;
86e1051a39Sopenharmony_ci        }
87e1051a39Sopenharmony_ci
88e1051a39Sopenharmony_ci        label = plab->parameter->value.octet_string->data;
89e1051a39Sopenharmony_ci        /* Stop label being freed when OAEP parameters are freed */
90e1051a39Sopenharmony_ci        plab->parameter->value.octet_string->data = NULL;
91e1051a39Sopenharmony_ci        labellen = plab->parameter->value.octet_string->length;
92e1051a39Sopenharmony_ci    }
93e1051a39Sopenharmony_ci
94e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0)
95e1051a39Sopenharmony_ci        goto err;
96e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0)
97e1051a39Sopenharmony_ci        goto err;
98e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
99e1051a39Sopenharmony_ci        goto err;
100e1051a39Sopenharmony_ci    if (label != NULL
101e1051a39Sopenharmony_ci            && EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0)
102e1051a39Sopenharmony_ci        goto err;
103e1051a39Sopenharmony_ci    /* Carry on */
104e1051a39Sopenharmony_ci    rv = 1;
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_ci err:
107e1051a39Sopenharmony_ci    RSA_OAEP_PARAMS_free(oaep);
108e1051a39Sopenharmony_ci    return rv;
109e1051a39Sopenharmony_ci}
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_cistatic int rsa_cms_encrypt(CMS_RecipientInfo *ri)
112e1051a39Sopenharmony_ci{
113e1051a39Sopenharmony_ci    const EVP_MD *md, *mgf1md;
114e1051a39Sopenharmony_ci    RSA_OAEP_PARAMS *oaep = NULL;
115e1051a39Sopenharmony_ci    ASN1_STRING *os = NULL;
116e1051a39Sopenharmony_ci    X509_ALGOR *alg;
117e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
118e1051a39Sopenharmony_ci    int pad_mode = RSA_PKCS1_PADDING, rv = 0, labellen;
119e1051a39Sopenharmony_ci    unsigned char *label;
120e1051a39Sopenharmony_ci
121e1051a39Sopenharmony_ci    if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) <= 0)
122e1051a39Sopenharmony_ci        return 0;
123e1051a39Sopenharmony_ci    if (pkctx != NULL) {
124e1051a39Sopenharmony_ci        if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
125e1051a39Sopenharmony_ci            return 0;
126e1051a39Sopenharmony_ci    }
127e1051a39Sopenharmony_ci    if (pad_mode == RSA_PKCS1_PADDING) {
128e1051a39Sopenharmony_ci        X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
129e1051a39Sopenharmony_ci        return 1;
130e1051a39Sopenharmony_ci    }
131e1051a39Sopenharmony_ci    /* Not supported */
132e1051a39Sopenharmony_ci    if (pad_mode != RSA_PKCS1_OAEP_PADDING)
133e1051a39Sopenharmony_ci        return 0;
134e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_get_rsa_oaep_md(pkctx, &md) <= 0)
135e1051a39Sopenharmony_ci        goto err;
136e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
137e1051a39Sopenharmony_ci        goto err;
138e1051a39Sopenharmony_ci    labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(pkctx, &label);
139e1051a39Sopenharmony_ci    if (labellen < 0)
140e1051a39Sopenharmony_ci        goto err;
141e1051a39Sopenharmony_ci    oaep = RSA_OAEP_PARAMS_new();
142e1051a39Sopenharmony_ci    if (oaep == NULL)
143e1051a39Sopenharmony_ci        goto err;
144e1051a39Sopenharmony_ci    if (!ossl_x509_algor_new_from_md(&oaep->hashFunc, md))
145e1051a39Sopenharmony_ci        goto err;
146e1051a39Sopenharmony_ci    if (!ossl_x509_algor_md_to_mgf1(&oaep->maskGenFunc, mgf1md))
147e1051a39Sopenharmony_ci        goto err;
148e1051a39Sopenharmony_ci    if (labellen > 0) {
149e1051a39Sopenharmony_ci        ASN1_OCTET_STRING *los;
150e1051a39Sopenharmony_ci
151e1051a39Sopenharmony_ci        oaep->pSourceFunc = X509_ALGOR_new();
152e1051a39Sopenharmony_ci        if (oaep->pSourceFunc == NULL)
153e1051a39Sopenharmony_ci            goto err;
154e1051a39Sopenharmony_ci        los = ASN1_OCTET_STRING_new();
155e1051a39Sopenharmony_ci        if (los == NULL)
156e1051a39Sopenharmony_ci            goto err;
157e1051a39Sopenharmony_ci        if (!ASN1_OCTET_STRING_set(los, label, labellen)) {
158e1051a39Sopenharmony_ci            ASN1_OCTET_STRING_free(los);
159e1051a39Sopenharmony_ci            goto err;
160e1051a39Sopenharmony_ci        }
161e1051a39Sopenharmony_ci        X509_ALGOR_set0(oaep->pSourceFunc, OBJ_nid2obj(NID_pSpecified),
162e1051a39Sopenharmony_ci                        V_ASN1_OCTET_STRING, los);
163e1051a39Sopenharmony_ci    }
164e1051a39Sopenharmony_ci    /* create string with pss parameter encoding. */
165e1051a39Sopenharmony_ci    if (!ASN1_item_pack(oaep, ASN1_ITEM_rptr(RSA_OAEP_PARAMS), &os))
166e1051a39Sopenharmony_ci         goto err;
167e1051a39Sopenharmony_ci    X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaesOaep), V_ASN1_SEQUENCE, os);
168e1051a39Sopenharmony_ci    os = NULL;
169e1051a39Sopenharmony_ci    rv = 1;
170e1051a39Sopenharmony_ci err:
171e1051a39Sopenharmony_ci    RSA_OAEP_PARAMS_free(oaep);
172e1051a39Sopenharmony_ci    ASN1_STRING_free(os);
173e1051a39Sopenharmony_ci    return rv;
174e1051a39Sopenharmony_ci}
175e1051a39Sopenharmony_ci
176e1051a39Sopenharmony_ciint ossl_cms_rsa_envelope(CMS_RecipientInfo *ri, int decrypt)
177e1051a39Sopenharmony_ci{
178e1051a39Sopenharmony_ci    assert(decrypt == 0 || decrypt == 1);
179e1051a39Sopenharmony_ci
180e1051a39Sopenharmony_ci    if (decrypt == 1)
181e1051a39Sopenharmony_ci        return rsa_cms_decrypt(ri);
182e1051a39Sopenharmony_ci
183e1051a39Sopenharmony_ci    if (decrypt == 0)
184e1051a39Sopenharmony_ci        return rsa_cms_encrypt(ri);
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
187e1051a39Sopenharmony_ci    return 0;
188e1051a39Sopenharmony_ci}
189e1051a39Sopenharmony_ci
190e1051a39Sopenharmony_cistatic int rsa_cms_sign(CMS_SignerInfo *si)
191e1051a39Sopenharmony_ci{
192e1051a39Sopenharmony_ci    int pad_mode = RSA_PKCS1_PADDING;
193e1051a39Sopenharmony_ci    X509_ALGOR *alg;
194e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pkctx = CMS_SignerInfo_get0_pkey_ctx(si);
195e1051a39Sopenharmony_ci    unsigned char aid[128];
196e1051a39Sopenharmony_ci    const unsigned char *pp = aid;
197e1051a39Sopenharmony_ci    size_t aid_len = 0;
198e1051a39Sopenharmony_ci    OSSL_PARAM params[2];
199e1051a39Sopenharmony_ci
200e1051a39Sopenharmony_ci    CMS_SignerInfo_get0_algs(si, NULL, NULL, NULL, &alg);
201e1051a39Sopenharmony_ci    if (pkctx != NULL) {
202e1051a39Sopenharmony_ci        if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
203e1051a39Sopenharmony_ci            return 0;
204e1051a39Sopenharmony_ci    }
205e1051a39Sopenharmony_ci    if (pad_mode == RSA_PKCS1_PADDING) {
206e1051a39Sopenharmony_ci        X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
207e1051a39Sopenharmony_ci        return 1;
208e1051a39Sopenharmony_ci    }
209e1051a39Sopenharmony_ci    /* We don't support it */
210e1051a39Sopenharmony_ci    if (pad_mode != RSA_PKCS1_PSS_PADDING)
211e1051a39Sopenharmony_ci        return 0;
212e1051a39Sopenharmony_ci
213e1051a39Sopenharmony_ci    params[0] = OSSL_PARAM_construct_octet_string(
214e1051a39Sopenharmony_ci        OSSL_SIGNATURE_PARAM_ALGORITHM_ID, aid, sizeof(aid));
215e1051a39Sopenharmony_ci    params[1] = OSSL_PARAM_construct_end();
216e1051a39Sopenharmony_ci
217e1051a39Sopenharmony_ci    if (EVP_PKEY_CTX_get_params(pkctx, params) <= 0)
218e1051a39Sopenharmony_ci        return 0;
219e1051a39Sopenharmony_ci    if ((aid_len = params[0].return_size) == 0)
220e1051a39Sopenharmony_ci        return 0;
221e1051a39Sopenharmony_ci    if (d2i_X509_ALGOR(&alg, &pp, aid_len) == NULL)
222e1051a39Sopenharmony_ci        return 0;
223e1051a39Sopenharmony_ci    return 1;
224e1051a39Sopenharmony_ci}
225e1051a39Sopenharmony_ci
226e1051a39Sopenharmony_cistatic int rsa_cms_verify(CMS_SignerInfo *si)
227e1051a39Sopenharmony_ci{
228e1051a39Sopenharmony_ci    int nid, nid2;
229e1051a39Sopenharmony_ci    X509_ALGOR *alg;
230e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pkctx = CMS_SignerInfo_get0_pkey_ctx(si);
231e1051a39Sopenharmony_ci    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pkctx);
232e1051a39Sopenharmony_ci
233e1051a39Sopenharmony_ci    CMS_SignerInfo_get0_algs(si, NULL, NULL, NULL, &alg);
234e1051a39Sopenharmony_ci    nid = OBJ_obj2nid(alg->algorithm);
235e1051a39Sopenharmony_ci    if (nid == EVP_PKEY_RSA_PSS)
236e1051a39Sopenharmony_ci        return ossl_rsa_pss_to_ctx(NULL, pkctx, alg, NULL) > 0;
237e1051a39Sopenharmony_ci    /* Only PSS allowed for PSS keys */
238e1051a39Sopenharmony_ci    if (EVP_PKEY_is_a(pkey, "RSA-PSS")) {
239e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_RSA, RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
240e1051a39Sopenharmony_ci        return 0;
241e1051a39Sopenharmony_ci    }
242e1051a39Sopenharmony_ci    if (nid == NID_rsaEncryption)
243e1051a39Sopenharmony_ci        return 1;
244e1051a39Sopenharmony_ci    /* Workaround for some implementation that use a signature OID */
245e1051a39Sopenharmony_ci    if (OBJ_find_sigid_algs(nid, NULL, &nid2)) {
246e1051a39Sopenharmony_ci        if (nid2 == NID_rsaEncryption)
247e1051a39Sopenharmony_ci            return 1;
248e1051a39Sopenharmony_ci    }
249e1051a39Sopenharmony_ci    return 0;
250e1051a39Sopenharmony_ci}
251e1051a39Sopenharmony_ci
252e1051a39Sopenharmony_ciint ossl_cms_rsa_sign(CMS_SignerInfo *si, int verify)
253e1051a39Sopenharmony_ci{
254e1051a39Sopenharmony_ci    assert(verify == 0 || verify == 1);
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_ci    if (verify == 1)
257e1051a39Sopenharmony_ci        return rsa_cms_verify(si);
258e1051a39Sopenharmony_ci
259e1051a39Sopenharmony_ci    if (verify == 0)
260e1051a39Sopenharmony_ci        return rsa_cms_sign(si);
261e1051a39Sopenharmony_ci
262e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
263e1051a39Sopenharmony_ci    return 0;
264e1051a39Sopenharmony_ci}
265