Migrate to openssl 1.1
[platform/core/security/yaca.git] / src / debug.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file debug.c
21  * @brief
22  */
23
24 #include <stdbool.h>
25 #include <string.h>
26
27 #include <openssl/err.h>
28 #include <openssl/pem.h>
29 #include <openssl/pkcs12.h>
30 #include <openssl/dsa.h>
31
32 #include <yaca_error.h>
33
34 #include "internal.h"
35 #include "debug.h"
36
37 // TODO any better idea than to use __thread?
38 static __thread yaca_error_cb error_cb = NULL;
39 static bool error_strings_loaded = false;
40 static const int GENERIC_REASON_MAX = 99;
41
42 API void yaca_debug_set_error_cb(yaca_error_cb fn)
43 {
44         error_cb = fn;
45 }
46
47 #define ERRORDESCRIBE(name) case name: return #name
48 API const char *yaca_debug_translate_error(yaca_error_e err)
49 {
50         switch (err) {
51         ERRORDESCRIBE(YACA_ERROR_NONE);
52         ERRORDESCRIBE(YACA_ERROR_INVALID_PARAMETER);
53         ERRORDESCRIBE(YACA_ERROR_OUT_OF_MEMORY);
54         ERRORDESCRIBE(YACA_ERROR_INTERNAL);
55         ERRORDESCRIBE(YACA_ERROR_DATA_MISMATCH);
56         ERRORDESCRIBE(YACA_ERROR_INVALID_PASSWORD);
57         default: return "Error not defined";
58         }
59 }
60 #undef ERRORDESCRIBE
61
62 void error_dump(const char *file, int line, const char *function, int code)
63 {
64         if (error_cb == NULL) {
65                 ERR_clear_error();
66                 return;
67         }
68
69         static const size_t BUF_SIZE = 512;
70         static const char ELLIPSIS[] = "...\n";
71         static const size_t ELLIPSIS_SIZE = sizeof(ELLIPSIS) / sizeof(ELLIPSIS[0]);
72         char buf[BUF_SIZE];
73         unsigned long err;
74         size_t written;
75         const char *err_str = yaca_debug_translate_error(code);
76         const char *sign = "";
77
78         if (code < 0) {
79                 code *= -1;
80                 sign = "-";
81         }
82
83         written = snprintf(buf, BUF_SIZE, "%s:%d %s() API error: %s0x%02X (%s)\n", file,
84                                            line, function, sign, code, err_str);
85
86         while ((err = ERR_get_error()) != 0 && written < BUF_SIZE - 1) {
87                 if (!error_strings_loaded) {
88                         /*
89                          * This function is thread-safe as long as static locks are
90                          * installed according to doc so calling it twice won't break
91                          * anything and I don't want to use synchronization mechanisms
92                          * here.
93                          */
94                         ERR_load_crypto_strings();
95                         error_strings_loaded = true;
96                 }
97
98                 ERR_error_string_n(err, buf + written, BUF_SIZE - written);
99                 written = strlen(buf); /* I trust you, openssl */
100                 if (written < BUF_SIZE - 1) {
101                         buf[written] = '\n';
102                         written++;
103                 }
104         }
105
106         if (written >= BUF_SIZE - 1) {
107                 strncpy(buf + BUF_SIZE - ELLIPSIS_SIZE, ELLIPSIS, ELLIPSIS_SIZE);
108                 written = BUF_SIZE - 1;
109                 ERR_clear_error();
110         }
111         buf[written] = '\0';
112
113         (*error_cb)(buf);
114 }
115
116 int error_handle(const char *file, int line, const char *function)
117 {
118         int ret = YACA_ERROR_NONE;
119         unsigned long err = ERR_peek_error();
120
121         if (err == 0)
122                 return YACA_ERROR_INTERNAL;
123
124         /* known errors */
125         switch (err) {
126 #if OPENSSL_VERSION_NUMBER > 0x10100000L
127         case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN):
128         case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PUBLIC_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN):
129         case ERR_PACK(ERR_LIB_PEM, PEM_F_GET_NAME, PEM_R_NO_START_LINE):
130 #else /* OPENSSL_VERSION_NUMBER > 0x10100000L */
131         case ERR_PACK(ERR_LIB_RSA, RSA_F_PKEY_RSA_CTRL, RSA_R_INVALID_KEYBITS):
132         case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PRIVATE_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN):
133         case ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_EAY_PUBLIC_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN):
134 #endif /* OPENSSL_VERSION_NUMBER > 0x10100000L */
135         case ERR_PACK(ERR_LIB_RSA, RSA_F_PKEY_RSA_CTRL, RSA_R_KEY_SIZE_TOO_SMALL):
136         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED):
137         case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE):
138         case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA):
139         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH):
140         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH):
141         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_WRONG_FINAL_BLOCK_LENGTH):
142         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_DERIVE_SET_PEER, EVP_R_DIFFERENT_PARAMETERS):
143         case ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE):
144         case ERR_PACK(ERR_LIB_DSA, DSA_F_PKEY_DSA_CTRL, DSA_R_INVALID_DIGEST_TYPE):
145                 ret = YACA_ERROR_INVALID_PARAMETER;
146                 break;
147         case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_TOO_LONG):
148         case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_HEADER_TOO_LONG):
149         case ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG):
150         {
151                 bool found_crypto_error = false;
152
153                 while ((err = ERR_get_error()) != 0)
154                         if (err == ERR_PACK(ERR_LIB_PKCS12, PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, PKCS12_R_DECODE_ERROR) ||
155                                 err == ERR_PACK(ERR_LIB_PKCS12, PKCS12_F_PKCS12_PBE_CRYPT, PKCS12_R_PKCS12_CIPHERFINAL_ERROR) ||
156                                 err == ERR_PACK(ERR_LIB_DSA, DSA_F_OLD_DSA_PRIV_DECODE, ERR_R_DSA_LIB) ||
157                                 err == ERR_PACK(ERR_LIB_RSA, RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB)) {
158                                 found_crypto_error = true;
159                                 break;
160                         }
161
162                 if (found_crypto_error)
163                         ret = YACA_ERROR_INVALID_PASSWORD;
164                 else
165                         ret = YACA_ERROR_INVALID_PARAMETER;
166
167                 break;
168         }
169         case ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT):
170         case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT):
171         case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ):
172         case ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO_PRIVATEKEY, PEM_R_BAD_PASSWORD_READ):
173         case ERR_PACK(ERR_LIB_PEM, PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ):
174                 ret = YACA_ERROR_INVALID_PASSWORD;
175                 break;
176         }
177
178         /* known rsa padding errors */
179         if (ret == YACA_ERROR_NONE && ERR_GET_LIB(err) == ERR_LIB_RSA) {
180                 switch (ERR_GET_FUNC(err)) {
181                 case RSA_F_CHECK_PADDING_MD:
182                 case RSA_F_RSA_PADDING_CHECK_NONE:
183                 case RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP:
184                 case RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1:
185                 case RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1:
186                 case RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2:
187                 case RSA_F_RSA_PADDING_CHECK_SSLV23:
188                 case RSA_F_RSA_PADDING_CHECK_X931:
189                 case RSA_F_RSA_PADDING_ADD_NONE:
190                 case RSA_F_RSA_PADDING_ADD_PKCS1_OAEP:
191                 case RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1:
192                 case RSA_F_RSA_PADDING_ADD_PKCS1_PSS:
193                 case RSA_F_RSA_PADDING_ADD_PKCS1_PSS_MGF1:
194                 case RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1:
195                 case RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2:
196                 case RSA_F_RSA_PADDING_ADD_SSLV23:
197                 case RSA_F_RSA_PADDING_ADD_X931:
198                         ret = YACA_ERROR_INVALID_PARAMETER;
199                         break;
200                 }
201         }
202
203         /* fatal errors */
204         int reason = ERR_GET_REASON(err);
205         if (ret == YACA_ERROR_NONE && reason <= GENERIC_REASON_MAX && (err & ERR_R_FATAL) > 0) {
206                 switch (reason) {
207                 case ERR_R_MALLOC_FAILURE:
208                         ret = YACA_ERROR_OUT_OF_MEMORY;
209                         break;
210                 case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
211                 case ERR_R_PASSED_NULL_PARAMETER:
212                         ret = YACA_ERROR_INVALID_PARAMETER;
213                         break;
214                 case ERR_R_INTERNAL_ERROR:
215                 case ERR_R_DISABLED:
216                         ret = YACA_ERROR_INTERNAL;
217                         break;
218                 }
219         }
220
221         /* neither known nor fatal, unknown */
222         if (ret == YACA_ERROR_NONE) {
223                 error_dump(file, line, function, YACA_ERROR_INTERNAL);
224                 ret = YACA_ERROR_INTERNAL;
225         }
226
227         /* remove all errors from queue */
228         ERR_clear_error();
229         return ret;
230 }