1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stddef.h>
6
7#include <lib/fdio/debug.h>
8#include <openssl/cipher.h>
9#include <openssl/digest.h>
10#include <openssl/err.h>
11#include <openssl/hkdf.h>
12#include <zircon/errors.h>
13#include <zircon/types.h>
14
15#include "error.h"
16
17#define ZXDEBUG 0
18
19namespace crypto {
20namespace {
21
22zx_status_t MapGlobalErrors(int reason) {
23    switch (reason) {
24
25    case ERR_R_MALLOC_FAILURE:
26        return ZX_ERR_NO_MEMORY;
27
28    case ERR_R_OVERFLOW:
29        return ZX_ERR_OUT_OF_RANGE;
30
31    default:
32        return ZX_ERR_INTERNAL;
33    }
34}
35
36zx_status_t MapCipherErrors(int reason) {
37    switch (reason) {
38
39    case CIPHER_R_CTRL_NOT_IMPLEMENTED:
40    case CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED:
41    case CIPHER_R_UNSUPPORTED_KEY_SIZE:
42    case CIPHER_R_UNSUPPORTED_NONCE_SIZE:
43        return ZX_ERR_NOT_SUPPORTED;
44
45    case CIPHER_R_AES_KEY_SETUP_FAILED:
46    case CIPHER_R_INITIALIZATION_ERROR:
47        return ZX_ERR_NO_RESOURCES;
48
49    case CIPHER_R_BAD_KEY_LENGTH:
50    case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
51    case CIPHER_R_INVALID_NONCE:
52    case CIPHER_R_INVALID_NONCE_SIZE:
53    case CIPHER_R_INVALID_OPERATION:
54    case CIPHER_R_INVALID_KEY_LENGTH:
55    case CIPHER_R_INPUT_NOT_INITIALIZED:
56    case CIPHER_R_OUTPUT_ALIASES_INPUT:
57    case CIPHER_R_TAG_TOO_LARGE:
58    case CIPHER_R_TOO_LARGE:
59        return ZX_ERR_INVALID_ARGS;
60
61    case CIPHER_R_NO_CIPHER_SET:
62    case CIPHER_R_NO_DIRECTION_SET:
63    case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
64        return ZX_ERR_BAD_STATE;
65
66    case CIPHER_R_BUFFER_TOO_SMALL:
67        return ZX_ERR_BUFFER_TOO_SMALL;
68
69    case CIPHER_R_BAD_DECRYPT:
70        return ZX_ERR_IO_DATA_INTEGRITY;
71
72    default:
73        return MapGlobalErrors(reason);
74    }
75}
76
77zx_status_t MapDigestErrors(int reason) {
78    switch (reason) {
79
80    case DIGEST_R_INPUT_NOT_INITIALIZED:
81        return ZX_ERR_INVALID_ARGS;
82
83    default:
84        return MapGlobalErrors(reason);
85    }
86}
87
88zx_status_t MapHkdfErrors(int reason) {
89    switch (reason) {
90
91    case HKDF_R_OUTPUT_TOO_LARGE:
92        return ZX_ERR_BUFFER_TOO_SMALL;
93
94    default:
95        return MapGlobalErrors(reason);
96    }
97}
98
99// Callback to print BoringSSL's error stack
100int xprintf_crypto_error(const char* str, size_t len, void* ctx) {
101    xprintf("    %s\n", str);
102    return 1;
103}
104
105} // namespace
106
107void xprintf_crypto_errors(zx_status_t* out) {
108    uint32_t packed = ERR_peek_last_error();
109    xprintf("BoringSSL error(s):\n");
110    ERR_print_errors_cb(xprintf_crypto_error, nullptr);
111    if (!out) {
112        return;
113    }
114    int lib = ERR_GET_LIB(packed);
115    int reason = ERR_GET_REASON(packed);
116    switch (lib) {
117    case ERR_R_CIPHER_LIB:
118        *out = MapCipherErrors(reason);
119        break;
120    case ERR_R_DIGEST_LIB:
121        *out = MapDigestErrors(reason);
122        break;
123    case ERR_R_HKDF_LIB:
124        *out = MapHkdfErrors(reason);
125        break;
126    default:
127        *out = MapGlobalErrors(reason);
128        break;
129    }
130}
131
132} // namespace crypto
133