1// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "private-lib-core.h"
16
17#include "ssl_pkey.h"
18#include "ssl_methods.h"
19#include "ssl_dbg.h"
20#include "ssl_port.h"
21
22/**
23 * @brief create a private key object according to input private key
24 */
25EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk, void *rngctx)
26{
27    int ret;
28    EVP_PKEY *pkey;
29
30    pkey = ssl_mem_zalloc(sizeof(EVP_PKEY));
31    if (!pkey) {
32        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "no enough memory > (pkey)");
33        goto no_mem;
34    }
35
36    if (ipk) {
37        pkey->method = ipk->method;
38    } else {
39        pkey->method = EVP_PKEY_method();
40    }
41
42    ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk, rngctx);
43    if (ret) {
44        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(new) return %d", ret);
45        goto failed;
46    }
47
48    return pkey;
49
50failed:
51    ssl_mem_free(pkey);
52no_mem:
53    return NULL;
54}
55
56/**
57 * @brief create a private key object
58 */
59EVP_PKEY* EVP_PKEY_new(void *rngctx)
60{
61    return __EVP_PKEY_new(NULL, rngctx);
62}
63
64/**
65 * @brief free a private key object
66 */
67void EVP_PKEY_free(EVP_PKEY *pkey)
68{
69    SSL_ASSERT3(pkey);
70
71    EVP_PKEY_METHOD_CALL(free, pkey);
72
73    ssl_mem_free(pkey);
74}
75
76/**
77 * @brief load a character key context into system context. If '*a' is pointed to the
78 *        private key, then load key into it. Or create a new private key object
79 */
80EVP_PKEY *d2i_PrivateKey(int type,
81                         EVP_PKEY **a,
82                         const unsigned char **pp,
83                         long length, void *rngctx)
84{
85    int m = 0;
86    int ret;
87    EVP_PKEY *pkey;
88
89    SSL_ASSERT2(pp);
90    SSL_ASSERT2(*pp);
91    SSL_ASSERT2(length);
92
93    if (a && *a) {
94        pkey = *a;
95    } else {
96        pkey = EVP_PKEY_new(rngctx);
97        if (!pkey) {
98            SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL");
99            goto failed1;
100        }
101
102        m = 1;
103    }
104
105    ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, (int)length);
106    if (ret) {
107        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret);
108        goto failed2;
109    }
110
111    if (a)
112        *a = pkey;
113
114    return pkey;
115
116failed2:
117    if (m)
118        EVP_PKEY_free(pkey);
119failed1:
120    return NULL;
121}
122
123/**
124 * @brief set the SSL context private key
125 */
126int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
127{
128    SSL_ASSERT1(ctx);
129    SSL_ASSERT1(pkey);
130
131    if (ctx->cert->pkey == pkey)
132        return 1;
133
134    if (ctx->cert->pkey)
135        EVP_PKEY_free(ctx->cert->pkey);
136
137    ctx->cert->pkey = pkey;
138
139    return 1;
140}
141
142/**
143 * @brief set the SSL private key
144 */
145int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
146{
147    SSL_ASSERT1(ssl);
148    SSL_ASSERT1(pkey);
149
150    if (ssl->cert->pkey == pkey)
151        return 1;
152
153    if (ssl->cert->pkey)
154        EVP_PKEY_free(ssl->cert->pkey);
155
156    ssl->cert->pkey = pkey;
157
158    return 1;
159}
160
161/**
162 * @brief load private key into the SSL context
163 */
164int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx,
165                                const unsigned char *d, long len)
166{
167    int ret;
168    EVP_PKEY *pk;
169
170    pk = d2i_PrivateKey(0, NULL, &d, len, ctx->rngctx);
171    if (!pk) {
172        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
173        goto failed1;
174    }
175
176    ret = SSL_CTX_use_PrivateKey(ctx, pk);
177    if (!ret) {
178        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_PrivateKey() return %d", ret);
179        goto failed2;
180    }
181
182    return 1;
183
184failed2:
185    EVP_PKEY_free(pk);
186failed1:
187    return 0;
188}
189
190/**
191 * @brief load private key into the SSL
192 */
193int SSL_use_PrivateKey_ASN1(int type, SSL *ssl,
194                                const unsigned char *d, long len)
195{
196    int ret;
197    EVP_PKEY *pk;
198
199    pk = d2i_PrivateKey(0, NULL, &d, len, ssl->ctx->rngctx);
200    if (!pk) {
201        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
202        goto failed1;
203    }
204
205    ret = SSL_use_PrivateKey(ssl, pk);
206    if (!ret) {
207        SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_PrivateKey() return %d", ret);
208        goto failed2;
209    }
210
211    return 1;
212
213failed2:
214    EVP_PKEY_free(pk);
215failed1:
216    return 0;
217}
218
219/**
220 * @brief load the private key file into SSL context
221 */
222int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
223{
224    return 0;
225}
226
227/**
228 * @brief load the private key file into SSL
229 */
230int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
231{
232    return 0;
233}
234
235/**
236 * @brief load the RSA ASN1 private key into SSL context
237 */
238int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len)
239{
240    return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len);
241}
242