• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace conscrypt {
28 
29 /**
30  * Utility methods for throwing JNI errors.
31  */
32 class Errors {
33 private:
Errors()34     Errors() {}
~Errors()35     ~Errors() {}
36 
37 public:
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      */
jniThrowException(JNIEnv * env,const char * className,const char * msg)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      */
jniThrowRuntimeException(JNIEnv * env,const char * msg)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      */
jniThrowNullPointerException(JNIEnv * env,const char * msg)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      */
jniThrowOutOfMemory(JNIEnv * env,const char * message)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      */
throwBadPaddingException(JNIEnv * env,const char * message)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      */
throwSignatureException(JNIEnv * env,const char * message)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      */
throwInvalidKeyException(JNIEnv * env,const char * message)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      */
throwIllegalBlockSizeException(JNIEnv * env,const char * message)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      */
throwNoSuchAlgorithmException(JNIEnv * env,const char * message)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      */
throwIOException(JNIEnv * env,const char * message)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      */
throwParsingException(JNIEnv * env,const char * message)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 
throwInvalidAlgorithmParameterException(JNIEnv * env,const char * message)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 
throwForAsn1Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))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 
throwForCipherError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))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 
throwForEvpError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))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 
throwForRsaError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))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 
throwForX509Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))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      */
throwSocketTimeoutException(JNIEnv * env,const char * message)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      */
throwSSLHandshakeExceptionStr(JNIEnv * env,const char * message)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      */
throwSSLExceptionStr(JNIEnv * env,const char * message)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      */
throwSSLProtocolExceptionStr(JNIEnv * env,const char * message)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