1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef CONSCRYPT_ERRORS_H_
18#define CONSCRYPT_ERRORS_H_
19
20#include "compat.h"
21#include "Trace.h"
22
23#include <errno.h>
24#include <jni.h>
25#include <openssl/ssl.h>
26
27namespace conscrypt {
28
29/**
30 * Utility methods for throwing JNI errors.
31 */
32class Errors {
33private:
34    Errors() {}
35    ~Errors() {}
36
37public:
38    /**
39     * Throw an exception with the specified class and an optional message.
40     *
41     * The "className" argument will be passed directly to FindClass, which
42     * takes strings with slashes (e.g. "java/lang/Object").
43     *
44     * If an exception is currently pending, we log a warning message and
45     * clear it.
46     *
47     * Returns 0 on success, nonzero if something failed (e.g. the exception
48     * class couldn't be found, so *an* exception will still be pending).
49     *
50     * Currently aborts the VM if it can't throw the exception.
51     */
52    static int jniThrowException(JNIEnv* env, const char* className, const char* msg) {
53        jclass exceptionClass = env->FindClass(className);
54
55        if (exceptionClass == nullptr) {
56            ALOGD("Unable to find exception class %s", className);
57            /* ClassNotFoundException now pending */
58            return -1;
59        }
60
61        if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
62            ALOGD("Failed throwing '%s' '%s'", className, msg);
63            /* an exception, most likely OOM, will now be pending */
64            return -1;
65        }
66
67        env->DeleteLocalRef(exceptionClass);
68        return 0;
69    }
70
71    /**
72     * Throw a java.lang.RuntimeException, with an optional message.
73     */
74    static int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
75        return jniThrowException(env, "java/lang/RuntimeException", msg);
76    }
77
78    /*
79     * Throw a java.lang.NullPointerException, with an optional message.
80     */
81    static int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
82        return jniThrowException(env, "java/lang/NullPointerException", msg);
83    }
84
85    /**
86     * Throws a OutOfMemoryError with the given string as a message.
87     */
88    static int jniThrowOutOfMemory(JNIEnv* env, const char* message) {
89        return jniThrowException(env, "java/lang/OutOfMemoryError", message);
90    }
91
92    /**
93     * Throws a BadPaddingException with the given string as a message.
94     */
95    static int throwBadPaddingException(JNIEnv* env, const char* message) {
96        JNI_TRACE("throwBadPaddingException %s", message);
97        return jniThrowException(env, "javax/crypto/BadPaddingException", message);
98    }
99
100    /**
101     * Throws a SignatureException with the given string as a message.
102     */
103    static int throwSignatureException(JNIEnv* env, const char* message) {
104        JNI_TRACE("throwSignatureException %s", message);
105        return jniThrowException(env, "java/security/SignatureException", message);
106    }
107
108    /**
109     * Throws a InvalidKeyException with the given string as a message.
110     */
111    static int throwInvalidKeyException(JNIEnv* env, const char* message) {
112        JNI_TRACE("throwInvalidKeyException %s", message);
113        return jniThrowException(env, "java/security/InvalidKeyException", message);
114    }
115
116    /**
117     * Throws a SignatureException with the given string as a message.
118     */
119    static int throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
120        JNI_TRACE("throwIllegalBlockSizeException %s", message);
121        return jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message);
122    }
123
124    /**
125     * Throws a NoSuchAlgorithmException with the given string as a message.
126     */
127    static int throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
128        JNI_TRACE("throwUnknownAlgorithmException %s", message);
129        return jniThrowException(env, "java/security/NoSuchAlgorithmException", message);
130    }
131
132    /**
133     * Throws an IOException with the given string as a message.
134     */
135    static int throwIOException(JNIEnv* env, const char* message) {
136        JNI_TRACE("throwIOException %s", message);
137        return jniThrowException(env, "java/io/IOException", message);
138    }
139
140    /**
141     * Throws a ParsingException with the given string as a message.
142     */
143    static int throwParsingException(JNIEnv* env, const char* message) {
144        return jniThrowException(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLX509CertificateFactory$ParsingException",
145                                 message);
146    }
147
148    static int throwInvalidAlgorithmParameterException(JNIEnv* env, const char* message) {
149        JNI_TRACE("throwInvalidAlgorithmParameterException %s", message);
150        return jniThrowException(env, "java/security/InvalidAlgorithmParameterException", message);
151    }
152
153    static int throwForAsn1Error(JNIEnv* env, int reason, const char* message,
154                                 int (*defaultThrow)(JNIEnv*, const char*)) {
155        switch (reason) {
156            case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE:
157#if defined(ASN1_R_UNABLE_TO_DECODE_RSA_KEY)
158            case ASN1_R_UNABLE_TO_DECODE_RSA_KEY:
159#endif
160#if defined(ASN1_R_WRONG_PUBLIC_KEY_TYPE)
161            case ASN1_R_WRONG_PUBLIC_KEY_TYPE:
162#endif
163#if defined(ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY)
164            case ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY:
165#endif
166#if defined(ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE)
167            case ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE:
168#endif
169                return throwInvalidKeyException(env, message);
170                break;
171            case ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM:
172            case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
173                return throwNoSuchAlgorithmException(env, message);
174                break;
175        }
176        return defaultThrow(env, message);
177    }
178
179    static int throwForCipherError(JNIEnv* env, int reason, const char* message,
180                                   int (*defaultThrow)(JNIEnv*, const char*)) {
181        switch (reason) {
182            case CIPHER_R_BAD_DECRYPT:
183                return throwBadPaddingException(env, message);
184                break;
185            case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
186            case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
187                return throwIllegalBlockSizeException(env, message);
188                break;
189            case CIPHER_R_AES_KEY_SETUP_FAILED:
190            case CIPHER_R_BAD_KEY_LENGTH:
191            case CIPHER_R_UNSUPPORTED_KEY_SIZE:
192                return throwInvalidKeyException(env, message);
193                break;
194        }
195        return defaultThrow(env, message);
196    }
197
198    static int throwForEvpError(JNIEnv* env, int reason, const char* message,
199                                int (*defaultThrow)(JNIEnv*, const char*)) {
200        switch (reason) {
201            case EVP_R_MISSING_PARAMETERS:
202                return throwInvalidKeyException(env, message);
203                break;
204            case EVP_R_UNSUPPORTED_ALGORITHM:
205#if defined(EVP_R_X931_UNSUPPORTED)
206            case EVP_R_X931_UNSUPPORTED:
207#endif
208                return throwNoSuchAlgorithmException(env, message);
209                break;
210#if defined(EVP_R_WRONG_PUBLIC_KEY_TYPE)
211            case EVP_R_WRONG_PUBLIC_KEY_TYPE:
212                return throwInvalidKeyException(env, message);
213                break;
214#endif
215#if defined(EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM)
216            case EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
217                return throwNoSuchAlgorithmException(env, message);
218                break;
219#endif
220            default:
221                return defaultThrow(env, message);
222                break;
223        }
224    }
225
226    static int throwForRsaError(JNIEnv* env, int reason, const char* message,
227                                int (*defaultThrow)(JNIEnv*, const char*)) {
228        switch (reason) {
229            case RSA_R_BLOCK_TYPE_IS_NOT_01:
230            case RSA_R_PKCS_DECODING_ERROR:
231#if defined(RSA_R_BLOCK_TYPE_IS_NOT_02)
232            case RSA_R_BLOCK_TYPE_IS_NOT_02:
233#endif
234                return throwBadPaddingException(env, message);
235                break;
236            case RSA_R_BAD_SIGNATURE:
237            case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
238            case RSA_R_INVALID_MESSAGE_LENGTH:
239            case RSA_R_WRONG_SIGNATURE_LENGTH:
240                return throwSignatureException(env, message);
241                break;
242            case RSA_R_UNKNOWN_ALGORITHM_TYPE:
243                return throwNoSuchAlgorithmException(env, message);
244                break;
245            case RSA_R_MODULUS_TOO_LARGE:
246            case RSA_R_NO_PUBLIC_EXPONENT:
247                return throwInvalidKeyException(env, message);
248                break;
249            case RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE:
250                return throwIllegalBlockSizeException(env, message);
251                break;
252        }
253        return defaultThrow(env, message);
254    }
255
256    static int throwForX509Error(JNIEnv* env, int reason, const char* message,
257                                 int (*defaultThrow)(JNIEnv*, const char*)) {
258        switch (reason) {
259            case X509_R_UNSUPPORTED_ALGORITHM:
260                return throwNoSuchAlgorithmException(env, message);
261                break;
262            default:
263                return defaultThrow(env, message);
264                break;
265        }
266    }
267
268    /*
269     * Checks this thread's OpenSSL error queue and throws a RuntimeException if
270     * necessary.
271     *
272     * @return true if an exception was thrown, false if not.
273     */
274    static bool throwExceptionIfNecessary(
275            JNIEnv* env, CONSCRYPT_UNUSED const char* location,
276            int (*defaultThrow)(JNIEnv*, const char*) = jniThrowRuntimeException) {
277        const char* file;
278        int line;
279        const char* data;
280        int flags;
281        unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
282        bool result = false;
283
284        if (error != 0) {
285            char message[256];
286            ERR_error_string_n(error, message, sizeof(message));
287            int library = ERR_GET_LIB(error);
288            int reason = ERR_GET_REASON(error);
289            JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s", location,
290                      error, library, reason, file, line, message,
291                      (flags & ERR_TXT_STRING) ? data : "(no data)");
292            switch (library) {
293                case ERR_LIB_RSA:
294                    throwForRsaError(env, reason, message, defaultThrow);
295                    break;
296                case ERR_LIB_ASN1:
297                    throwForAsn1Error(env, reason, message, defaultThrow);
298                    break;
299                case ERR_LIB_CIPHER:
300                    throwForCipherError(env, reason, message, defaultThrow);
301                    break;
302                case ERR_LIB_EVP:
303                    throwForEvpError(env, reason, message, defaultThrow);
304                    break;
305                case ERR_LIB_X509:
306                    throwForX509Error(env, reason, message, defaultThrow);
307                    break;
308                case ERR_LIB_DSA:
309                    throwInvalidKeyException(env, message);
310                    break;
311                default:
312                    defaultThrow(env, message);
313                    break;
314            }
315            result = true;
316        }
317
318        ERR_clear_error();
319        return result;
320    }
321
322    /**
323     * Throws an SocketTimeoutException with the given string as a message.
324     */
325    static int throwSocketTimeoutException(JNIEnv* env, const char* message) {
326        JNI_TRACE("throwSocketTimeoutException %s", message);
327        return jniThrowException(env, "java/net/SocketTimeoutException", message);
328    }
329
330    /**
331     * Throws a javax.net.ssl.SSLException with the given string as a message.
332     */
333    static int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message) {
334        JNI_TRACE("throwSSLExceptionStr %s", message);
335        return jniThrowException(env, "javax/net/ssl/SSLHandshakeException", message);
336    }
337
338    /**
339     * Throws a javax.net.ssl.SSLException with the given string as a message.
340     */
341    static int throwSSLExceptionStr(JNIEnv* env, const char* message) {
342        JNI_TRACE("throwSSLExceptionStr %s", message);
343        return jniThrowException(env, "javax/net/ssl/SSLException", message);
344    }
345
346    /**
347     * Throws a javax.net.ssl.SSLProcotolException with the given string as a message.
348     */
349    static int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
350        JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
351        return jniThrowException(env, "javax/net/ssl/SSLProtocolException", message);
352    }
353
354    /**
355     * Throws an SSLException with a message constructed from the current
356     * SSL errors. This will also log the errors.
357     *
358     * @param env the JNI environment
359     * @param ssl the possibly null SSL
360     * @param sslErrorCode error code returned from SSL_get_error() or
361     * SSL_ERROR_NONE to probe with ERR_get_error
362     * @param message null-ok; general error message
363     */
364    static int throwSSLExceptionWithSslErrors(
365            JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message,
366            int (*actualThrow)(JNIEnv*, const char*) = throwSSLExceptionStr) {
367        if (message == nullptr) {
368            message = "SSL error";
369        }
370
371        // First consult the SSL error code for the general message.
372        const char* sslErrorStr = nullptr;
373        switch (sslErrorCode) {
374            case SSL_ERROR_NONE:
375                if (ERR_peek_error() == 0) {
376                    sslErrorStr = "OK";
377                } else {
378                    sslErrorStr = "";
379                }
380                break;
381            case SSL_ERROR_SSL:
382                sslErrorStr = "Failure in SSL library, usually a protocol error";
383                break;
384            case SSL_ERROR_WANT_READ:
385                sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
386                break;
387            case SSL_ERROR_WANT_WRITE:
388                sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
389                break;
390            case SSL_ERROR_WANT_X509_LOOKUP:
391                sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
392                break;
393            case SSL_ERROR_SYSCALL:
394                sslErrorStr = "I/O error during system call";
395                break;
396            case SSL_ERROR_ZERO_RETURN:
397                sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
398                break;
399            case SSL_ERROR_WANT_CONNECT:
400                sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
401                break;
402            case SSL_ERROR_WANT_ACCEPT:
403                sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
404                break;
405            default:
406                sslErrorStr = "Unknown SSL error";
407        }
408
409        // Prepend either our explicit message or a default one.
410        char* str;
411        if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
412            // problem with asprintf, just throw argument message, log everything
413            int ret = actualThrow(env, message);
414            ALOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
415            ERR_clear_error();
416            return ret;
417        }
418
419        char* allocStr = str;
420
421        // For protocol errors, SSL might have more information.
422        if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
423            // Append each error as an additional line to the message.
424            for (;;) {
425                char errStr[256];
426                const char* file;
427                int line;
428                const char* data;
429                int flags;
430                unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
431                if (err == 0) {
432                    break;
433                }
434
435                ERR_error_string_n(err, errStr, sizeof(errStr));
436
437                int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
438                                   (allocStr == nullptr) ? "" : allocStr, errStr, file, line,
439                                   (flags & ERR_TXT_STRING) ? data : "(no data)", flags);
440
441                if (ret < 0) {
442                    break;
443                }
444
445                free(allocStr);
446                allocStr = str;
447            }
448            // For errors during system calls, errno might be our friend.
449        } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
450            if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
451                free(allocStr);
452                allocStr = str;
453            }
454            // If the error code is invalid, print it.
455        } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
456            if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
457                free(allocStr);
458                allocStr = str;
459            }
460        }
461
462        int ret;
463        if (sslErrorCode == SSL_ERROR_SSL) {
464            ret = throwSSLProtocolExceptionStr(env, allocStr);
465        } else {
466            ret = actualThrow(env, allocStr);
467        }
468
469        ALOGV("%s", allocStr);
470        free(allocStr);
471        ERR_clear_error();
472        return ret;
473    }
474};
475
476}  // namespace conscrypt
477
478#endif  // CONSCRYPT_ERRORS_H_
479