2 * Copyright (C) 2012-2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "android_private_key.h"
18 #include "../android_jni.h"
19 #include <utils/debug.h>
20 #include <asn1/asn1.h>
22 typedef struct private_private_key_t private_private_key_t
;
25 * Private data of a android_private_key_t object.
27 struct private_private_key_t
{
35 * reference to the Java PrivateKey object
40 * Java class used to build signatures
42 jclass signature_class
;
45 * public key that belongs to this private key
55 METHOD(private_key_t
, sign
, bool,
56 private_private_key_t
*this, signature_scheme_t scheme
,
57 chunk_t data
, chunk_t
*signature
)
61 const char *method
= NULL
;
64 jbyteArray jdata
, jsigarray
;
66 switch (this->pubkey
->get_type(this->pubkey
))
71 case SIGN_RSA_EMSA_PKCS1_NULL
:
72 method
= "NONEwithRSA";
74 case SIGN_RSA_EMSA_PKCS1_MD5
:
75 method
= "MD5withRSA";
77 case SIGN_RSA_EMSA_PKCS1_SHA1
:
78 method
= "SHA1withRSA";
80 case SIGN_RSA_EMSA_PKCS1_SHA224
:
81 method
= "SHA224withRSA";
83 case SIGN_RSA_EMSA_PKCS1_SHA256
:
84 method
= "SHA256withRSA";
86 case SIGN_RSA_EMSA_PKCS1_SHA384
:
87 method
= "SHA384withRSA";
89 case SIGN_RSA_EMSA_PKCS1_SHA512
:
90 method
= "SHA512withRSA";
99 case SIGN_ECDSA_WITH_SHA1_DER
:
100 method
= "SHA1withECDSA";
102 case SIGN_ECDSA_WITH_SHA256_DER
:
104 method
= "SHA256withECDSA";
106 case SIGN_ECDSA_WITH_SHA384_DER
:
108 method
= "SHA384withECDSA";
110 case SIGN_ECDSA_WITH_SHA512_DER
:
112 method
= "SHA512withECDSA";
123 DBG1(DBG_LIB
, "signature scheme %N not supported via JNI",
124 signature_scheme_names
, scheme
);
128 androidjni_attach_thread(&env
);
129 /* we use java.security.Signature to create the signature without requiring
130 * access to the actual private key */
131 method_id
= (*env
)->GetStaticMethodID(env
, this->signature_class
,
132 "getInstance", "(Ljava/lang/String;)Ljava/security/Signature;");
137 jmethod
= (*env
)->NewStringUTF(env
, method
);
142 jsignature
= (*env
)->CallStaticObjectMethod(env
, this->signature_class
,
148 method_id
= (*env
)->GetMethodID(env
, this->signature_class
, "initSign",
149 "(Ljava/security/PrivateKey;)V");
154 (*env
)->CallVoidMethod(env
, jsignature
, method_id
, this->key
);
155 if (androidjni_exception_occurred(env
))
159 method_id
= (*env
)->GetMethodID(env
, this->signature_class
, "update",
165 jdata
= byte_array_from_chunk(env
, data
);
166 (*env
)->CallVoidMethod(env
, jsignature
, method_id
, jdata
);
167 if (androidjni_exception_occurred(env
))
171 method_id
= (*env
)->GetMethodID(env
, this->signature_class
, "sign",
177 jsigarray
= (*env
)->CallObjectMethod(env
, jsignature
, method_id
);
182 if (this->pubkey
->get_type(this->pubkey
) == KEY_ECDSA
)
184 chunk_t encoded
, parse
, r
, s
;
203 /* we get an ASN.1 encoded sequence of integers r and s */
204 parse
= encoded
= chunk_from_byte_array(env
, jsigarray
);
205 if (asn1_unwrap(&parse
, &parse
) != ASN1_SEQUENCE
||
206 asn1_unwrap(&parse
, &r
) != ASN1_INTEGER
||
207 asn1_unwrap(&parse
, &s
) != ASN1_INTEGER
)
209 chunk_free(&encoded
);
212 r
= chunk_skip_zero(r
);
213 s
= chunk_skip_zero(s
);
214 if (r
.len
> len
|| s
.len
> len
)
216 chunk_free(&encoded
);
220 /* concatenate r and s (forced to the defined length) */
221 *signature
= chunk_alloc(2*len
);
222 memset(signature
->ptr
, 0, signature
->len
);
223 memcpy(signature
->ptr
+ (len
- r
.len
), r
.ptr
, r
.len
);
224 memcpy(signature
->ptr
+ len
+ (len
- s
.len
), s
.ptr
, s
.len
);
225 chunk_free(&encoded
);
229 *signature
= chunk_from_byte_array(env
, jsigarray
);
234 *signature
= chunk_from_byte_array(env
, jsigarray
);
236 androidjni_detach_thread();
240 DBG1(DBG_LIB
, "failed to build %N signature via JNI",
241 signature_scheme_names
, scheme
);
242 androidjni_exception_occurred(env
);
243 androidjni_detach_thread();
247 METHOD(private_key_t
, get_type
, key_type_t
,
248 private_private_key_t
*this)
250 return this->pubkey
->get_type(this->pubkey
);
253 METHOD(private_key_t
, decrypt
, bool,
254 private_private_key_t
*this, encryption_scheme_t scheme
,
255 chunk_t crypto
, chunk_t
*plain
)
257 DBG1(DBG_LIB
, "private key decryption is currently not supported via JNI");
261 METHOD(private_key_t
, get_keysize
, int,
262 private_private_key_t
*this)
264 return this->pubkey
->get_keysize(this->pubkey
);
267 METHOD(private_key_t
, get_public_key
, public_key_t
*,
268 private_private_key_t
*this)
270 return this->pubkey
->get_ref(this->pubkey
);
273 METHOD(private_key_t
, get_encoding
, bool,
274 private_private_key_t
*this, cred_encoding_type_t type
,
280 METHOD(private_key_t
, get_fingerprint
, bool,
281 private_private_key_t
*this, cred_encoding_type_t type
, chunk_t
*fp
)
283 return this->pubkey
->get_fingerprint(this->pubkey
, type
, fp
);
286 METHOD(private_key_t
, get_ref
, private_key_t
*,
287 private_private_key_t
*this)
290 return &this->public;
293 METHOD(private_key_t
, destroy
, void,
294 private_private_key_t
*this)
296 if (ref_put(&this->ref
))
300 androidjni_attach_thread(&env
);
301 if (android_sdk_version
== ANDROID_JELLY_BEAN
)
302 { /* there is a bug in JB that causes a SIGSEGV if the key object is
303 * garbage collected so we intentionally leak the reference to it */
304 DBG1(DBG_LIB
, "intentionally leaking private key reference due to "
305 "a bug in the framework");
309 (*env
)->DeleteGlobalRef(env
, this->key
);
311 (*env
)->DeleteGlobalRef(env
, this->signature_class
);
312 androidjni_detach_thread();
313 this->pubkey
->destroy(this->pubkey
);
321 private_key_t
*android_private_key_create(jobject key
, public_key_t
*pubkey
)
324 private_private_key_t
*this;
328 .get_type
= _get_type
,
331 .get_keysize
= _get_keysize
,
332 .get_public_key
= _get_public_key
,
333 .belongs_to
= private_key_belongs_to
,
334 .equals
= private_key_equals
,
335 .get_fingerprint
= _get_fingerprint
,
336 .has_fingerprint
= private_key_has_fingerprint
,
337 .get_encoding
= _get_encoding
,
351 /* in ICS we could simply call getEncoded and use the PKCS#8/DER encoded
352 * private key, since JB that's not possible as there is no direct access
353 * to private keys anymore (as these could now be hardware backed) */
354 androidjni_attach_thread(&env
);
355 this->key
= (*env
)->NewGlobalRef(env
, key
);
356 this->signature_class
= (*env
)->NewGlobalRef(env
, (*env
)->FindClass(env
,
357 "java/security/Signature"));
358 androidjni_detach_thread();
359 return &this->public;