Skip to content

Commit

Permalink
[AndroidCrypto] Implement Root (read-only) and CurrentUser/My certifi…
Browse files Browse the repository at this point in the history
…cate stores (#48862)
  • Loading branch information
elinor-fung authored Mar 19, 2021
1 parent 54d8c84 commit eae9a1d
Show file tree
Hide file tree
Showing 28 changed files with 1,374 additions and 250 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ internal enum PAL_KeyAlgorithm
DSA,
EC,
RSA,
UnknownAlgorithm = -1,
}

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509PublicKey")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
internal static partial class AndroidCrypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreAddCertificate")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreAddCertificate(
SafeX509StoreHandle store,
SafeX509Handle cert,
string hashString);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreAddCertificateWithPrivateKey(
SafeX509StoreHandle store,
SafeX509Handle cert,
SafeKeyHandle key,
PAL_KeyAlgorithm algorithm,
string hashString);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreContainsCertificate")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreContainsCertificate(
SafeX509StoreHandle store,
SafeX509Handle cert,
string hashString);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreEnumerateCertificates")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreEnumerateCertificates(
SafeX509StoreHandle storeHandle,
delegate* unmanaged<void*, void*, Interop.AndroidCrypto.PAL_KeyAlgorithm, void*, void> callback,
void *callbackContext);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreEnumerateTrustedCertificates")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreEnumerateTrustedCertificates(
byte systemOnly,
delegate* unmanaged<void*, void*, void> callback,
void *callbackContext);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreOpenDefault")]
internal static extern unsafe SafeX509StoreHandle X509StoreOpenDefault();

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509StoreRemoveCertificate")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern unsafe bool X509StoreRemoveCertificate(
SafeX509StoreHandle store,
SafeX509Handle cert,
string hashString);
}
}

namespace System.Security.Cryptography.X509Certificates
{
internal sealed class SafeX509StoreHandle : Interop.JObjectLifetime.SafeJObjectHandle
{
public SafeX509StoreHandle()
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ set(NATIVECRYPTO_SOURCES
pal_ssl.c
pal_sslstream.c
pal_x509.c
pal_x509store.c
)

add_library(System.Security.Cryptography.Native.Android
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ EC_KEY* AndroidCryptoNative_NewEcKey(jobject curveParameters, jobject keyPair)
return keyInfo;
}

EC_KEY* AndroidCryptoNative_NewEcKeyFromPublicKey(JNIEnv *env, jobject /*ECPublicKey*/ publicKey)
EC_KEY* AndroidCryptoNative_NewEcKeyFromKeys(JNIEnv *env, jobject /*ECPublicKey*/ publicKey, jobject /*ECPrivateKey*/ privateKey)
{
assert(publicKey != NULL);

if (!(*env)->IsInstanceOf(env, publicKey, g_ECPublicKeyClass))
return NULL;

jobject curveParameters = (*env)->CallObjectMethod(env, publicKey, g_ECPublicKeyGetParams);
return AndroidCryptoNative_NewEcKey(ToGRef(env, curveParameters), AndroidCryptoNative_CreateKeyPair(env, publicKey, NULL));
return AndroidCryptoNative_NewEcKey(ToGRef(env, curveParameters), AndroidCryptoNative_CreateKeyPair(env, publicKey, privateKey));
}

#pragma clang diagnostic push
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ typedef struct EC_KEY
} EC_KEY;

EC_KEY* AndroidCryptoNative_NewEcKey(jobject curveParameters, jobject keyPair);
EC_KEY* AndroidCryptoNative_NewEcKeyFromPublicKey(JNIEnv *env, jobject /*ECPublicKey*/ publicKey);
EC_KEY* AndroidCryptoNative_NewEcKeyFromKeys(JNIEnv *env, jobject /*ECPublicKey*/ publicKey, jobject /*ECPrivateKey*/ privateKey);

/*
Cleans up and deletes an EC_KEY instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ jmethodID g_sslCtxGetDefaultSslParamsMethod;
jclass g_GCMParameterSpecClass;
jmethodID g_GCMParameterSpecCtor;

// java/security/interfaces/DSAKey
jclass g_DSAKeyClass;

// java/security/interfaces/ECKey
jclass g_ECKeyClass;

// java/security/interfaces/RSAKey
jclass g_RSAKeyClass;
jmethodID g_RSAKeyGetModulus;
Expand All @@ -106,6 +112,27 @@ jmethodID g_keyPairGenInitializeWithParamsMethod;
jmethodID g_keyPairGenInitializeMethod;
jmethodID g_keyPairGenGenKeyPairMethod;

// java/security/KeyStore
jclass g_KeyStoreClass;
jmethodID g_KeyStoreGetInstance;
jmethodID g_KeyStoreAliases;
jmethodID g_KeyStoreContainsAlias;
jmethodID g_KeyStoreDeleteEntry;
jmethodID g_KeyStoreGetCertificate;
jmethodID g_KeyStoreGetEntry;
jmethodID g_KeyStoreLoad;
jmethodID g_KeyStoreSetCertificateEntry;
jmethodID g_KeyStoreSetKeyEntry;

// java/security/KeyStore$PrivateKeyEntry
jclass g_PrivateKeyEntryClass;
jmethodID g_PrivateKeyEntryGetCertificate;
jmethodID g_PrivateKeyEntryGetPrivateKey;

// java/security/KeyStore$TrustedCertificateEntry
jclass g_TrustedCertificateEntryClass;
jmethodID g_TrustedCertificateEntryGetTrustedCertificate;

// java/security/Signature
jclass g_SignatureClass;
jmethodID g_SignatureGetInstance;
Expand All @@ -130,6 +157,7 @@ jmethodID g_CertPathGetEncoded;

// java/security/cert/X509Certificate
jclass g_X509CertClass;
jmethodID g_X509CertEquals;
jmethodID g_X509CertGetEncoded;
jmethodID g_X509CertGetPublicKey;

Expand Down Expand Up @@ -254,6 +282,11 @@ jmethodID g_CollectionSize;
jclass g_DateClass;
jmethodID g_DateGetTime;

// java/util/Enumeration
jclass g_Enumeration;
jmethodID g_EnumerationHasMoreElements;
jmethodID g_EnumerationNextElement;

// java/util/Iterator
jclass g_IteratorClass;
jmethodID g_IteratorHasNext;
Expand Down Expand Up @@ -537,9 +570,14 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
g_CertPathClass = GetClassGRef(env, "java/security/cert/CertPath");
g_CertPathGetEncoded = GetMethod(env, false, g_CertPathClass, "getEncoded", "(Ljava/lang/String;)[B");

g_X509CertClass = GetClassGRef(env, "java/security/cert/X509Certificate");
g_X509CertGetEncoded = GetMethod(env, false, g_X509CertClass, "getEncoded", "()[B");
g_X509CertGetPublicKey = GetMethod(env, false, g_X509CertClass, "getPublicKey", "()Ljava/security/PublicKey;");
g_X509CertClass = GetClassGRef(env, "java/security/cert/X509Certificate");
g_X509CertEquals = GetMethod(env, false, g_X509CertClass, "equals", "(Ljava/lang/Object;)Z");
g_X509CertGetEncoded = GetMethod(env, false, g_X509CertClass, "getEncoded", "()[B");
g_X509CertGetPublicKey = GetMethod(env, false, g_X509CertClass, "getPublicKey", "()Ljava/security/PublicKey;");

g_DSAKeyClass = GetClassGRef(env, "java/security/interfaces/DSAKey");

g_ECKeyClass = GetClassGRef(env, "java/security/interfaces/ECKey");

g_RSAKeyClass = GetClassGRef(env, "java/security/interfaces/RSAKey");
g_RSAKeyGetModulus = GetMethod(env, false, g_RSAKeyClass, "getModulus", "()Ljava/math/BigInteger;");
Expand All @@ -558,6 +596,24 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
g_keyPairGenInitializeWithParamsMethod = GetMethod(env, false, g_keyPairGenClass, "initialize", "(Ljava/security/spec/AlgorithmParameterSpec;)V");
g_keyPairGenGenKeyPairMethod = GetMethod(env, false, g_keyPairGenClass, "genKeyPair", "()Ljava/security/KeyPair;");

g_KeyStoreClass = GetClassGRef(env, "java/security/KeyStore");
g_KeyStoreGetInstance = GetMethod(env, true, g_KeyStoreClass, "getInstance", "(Ljava/lang/String;)Ljava/security/KeyStore;");
g_KeyStoreAliases = GetMethod(env, false, g_KeyStoreClass, "aliases", "()Ljava/util/Enumeration;");
g_KeyStoreContainsAlias = GetMethod(env, false, g_KeyStoreClass, "containsAlias", "(Ljava/lang/String;)Z");
g_KeyStoreDeleteEntry = GetMethod(env, false, g_KeyStoreClass, "deleteEntry", "(Ljava/lang/String;)V");
g_KeyStoreGetCertificate = GetMethod(env, false, g_KeyStoreClass, "getCertificate", "(Ljava/lang/String;)Ljava/security/cert/Certificate;");
g_KeyStoreGetEntry = GetMethod(env, false, g_KeyStoreClass, "getEntry", "(Ljava/lang/String;Ljava/security/KeyStore$ProtectionParameter;)Ljava/security/KeyStore$Entry;");
g_KeyStoreLoad = GetMethod(env, false, g_KeyStoreClass, "load", "(Ljava/io/InputStream;[C)V");
g_KeyStoreSetCertificateEntry = GetMethod(env, false, g_KeyStoreClass, "setCertificateEntry", "(Ljava/lang/String;Ljava/security/cert/Certificate;)V");
g_KeyStoreSetKeyEntry = GetMethod(env, false, g_KeyStoreClass, "setKeyEntry", "(Ljava/lang/String;Ljava/security/Key;[C[Ljava/security/cert/Certificate;)V");

g_PrivateKeyEntryClass = GetClassGRef(env, "java/security/KeyStore$PrivateKeyEntry");
g_PrivateKeyEntryGetCertificate = GetMethod(env, false, g_PrivateKeyEntryClass, "getCertificate", "()Ljava/security/cert/Certificate;");
g_PrivateKeyEntryGetPrivateKey = GetMethod(env, false, g_PrivateKeyEntryClass, "getPrivateKey", "()Ljava/security/PrivateKey;");

g_TrustedCertificateEntryClass = GetClassGRef(env, "java/security/KeyStore$TrustedCertificateEntry");
g_TrustedCertificateEntryGetTrustedCertificate = GetMethod(env, false, g_TrustedCertificateEntryClass, "getTrustedCertificate", "()Ljava/security/cert/Certificate;");

g_SignatureClass = GetClassGRef(env, "java/security/Signature");
g_SignatureGetInstance = GetMethod(env, true, g_SignatureClass, "getInstance", "(Ljava/lang/String;)Ljava/security/Signature;");
g_SignatureInitSign = GetMethod(env, false, g_SignatureClass, "initSign", "(Ljava/security/PrivateKey;)V");
Expand Down Expand Up @@ -665,6 +721,10 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
g_DateClass = GetClassGRef(env, "java/util/Date");
g_DateGetTime = GetMethod(env, false, g_DateClass, "getTime", "()J");

g_Enumeration = GetClassGRef(env, "java/util/Enumeration");
g_EnumerationHasMoreElements = GetMethod(env, false, g_Enumeration, "hasMoreElements", "()Z");
g_EnumerationNextElement = GetMethod(env, false, g_Enumeration, "nextElement", "()Ljava/lang/Object;");

g_IteratorClass = GetClassGRef(env, "java/util/Iterator");
g_IteratorHasNext = GetMethod(env, false, g_IteratorClass, "hasNext", "()Z");
g_IteratorNext = GetMethod(env, false, g_IteratorClass, "next", "()Ljava/lang/Object;");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,16 @@ extern jmethodID g_CertPathGetEncoded;

// java/security/cert/X509Certificate
extern jclass g_X509CertClass;
extern jmethodID g_X509CertEquals;
extern jmethodID g_X509CertGetEncoded;
extern jmethodID g_X509CertGetPublicKey;

// java/security/interfaces/DSAKey
extern jclass g_DSAKeyClass;

// java/security/interfaces/ECKey
extern jclass g_ECKeyClass;

// java/security/interfaces/RSAKey
extern jclass g_RSAKeyClass;
extern jmethodID g_RSAKeyGetModulus;
Expand All @@ -133,6 +140,27 @@ extern jmethodID g_keyPairGenInitializeMethod;
extern jmethodID g_keyPairGenInitializeWithParamsMethod;
extern jmethodID g_keyPairGenGenKeyPairMethod;

// java/security/KeyStore
extern jclass g_KeyStoreClass;
extern jmethodID g_KeyStoreGetInstance;
extern jmethodID g_KeyStoreAliases;
extern jmethodID g_KeyStoreContainsAlias;
extern jmethodID g_KeyStoreDeleteEntry;
extern jmethodID g_KeyStoreGetCertificate;
extern jmethodID g_KeyStoreGetEntry;
extern jmethodID g_KeyStoreLoad;
extern jmethodID g_KeyStoreSetCertificateEntry;
extern jmethodID g_KeyStoreSetKeyEntry;

// java/security/KeyStore$PrivateKeyEntry
extern jclass g_PrivateKeyEntryClass;
extern jmethodID g_PrivateKeyEntryGetCertificate;
extern jmethodID g_PrivateKeyEntryGetPrivateKey;

// java/security/KeyStore$TrustedCertificateEntry
extern jclass g_TrustedCertificateEntryClass;
extern jmethodID g_TrustedCertificateEntryGetTrustedCertificate;

// java/security/Signature
extern jclass g_SignatureClass;
extern jmethodID g_SignatureGetInstance;
Expand Down Expand Up @@ -263,6 +291,11 @@ extern jmethodID g_CollectionSize;
extern jclass g_DateClass;
extern jmethodID g_DateGetTime;

// java/util/Enumeration
extern jclass g_Enumeration;
extern jmethodID g_EnumerationHasMoreElements;
extern jmethodID g_EnumerationNextElement;

// java/util/Iterator
extern jclass g_IteratorClass;
extern jmethodID g_IteratorHasNext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ PALEXPORT RSA* AndroidCryptoNative_DecodeRsaSubjectPublicKeyInfo(uint8_t* buf, i
return FAIL;
}

RSA* rsa = AndroidCryptoNative_NewRsaFromPublicKey(env, publicKey);
RSA* rsa = AndroidCryptoNative_NewRsaFromKeys(env, publicKey, NULL /*privateKey*/);
(*env)->DeleteLocalRef(env, publicKey);

return rsa;
Expand Down Expand Up @@ -385,15 +385,16 @@ PALEXPORT int32_t AndroidCryptoNative_SetRsaParameters(RSA* rsa,
return CheckJNIExceptions(env) ? FAIL : SUCCESS;
}

RSA* AndroidCryptoNative_NewRsaFromPublicKey(JNIEnv* env, jobject /*RSAPublicKey*/ key)
RSA* AndroidCryptoNative_NewRsaFromKeys(JNIEnv* env, jobject /*RSAPublicKey*/ publicKey, jobject /*RSAPrivateKey*/ privateKey)
{
if (!(*env)->IsInstanceOf(env, key, g_RSAPublicKeyClass))
if (!(*env)->IsInstanceOf(env, publicKey, g_RSAPublicKeyClass))
return NULL;

jobject modulus = (*env)->CallObjectMethod(env, key, g_RSAKeyGetModulus);
jobject modulus = (*env)->CallObjectMethod(env, publicKey, g_RSAKeyGetModulus);

RSA* ret = AndroidCryptoNative_RsaCreate();
ret->publicKey = AddGRef(env, key);
ret->publicKey = AddGRef(env, publicKey);
ret->privateKey = AddGRef(env, privateKey);
ret->keyWidthInBits = AndroidCryptoNative_GetBigNumBytes(modulus) * 8;

(*env)->DeleteLocalRef(env, modulus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ PALEXPORT int32_t AndroidCryptoNative_SetRsaParameters(RSA* rsa,
uint8_t* p, int32_t pLength, uint8_t* dmp1, int32_t dmp1Length, uint8_t* q, int32_t qLength,
uint8_t* dmq1, int32_t dmq1Length, uint8_t* iqmp, int32_t iqmpLength);

RSA* AndroidCryptoNative_NewRsaFromKeys(JNIEnv* env, jobject /*RSAPublicKey*/ publicKey, jobject /*RSAPrivateKey*/ privateKey);
RSA* AndroidCryptoNative_NewRsaFromPublicKey(JNIEnv* env, jobject /*RSAPublicKey*/ key);
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,13 @@ void* AndroidCryptoNative_X509PublicKey(jobject /*X509Certificate*/ cert, PAL_Ke
switch (algorithm)
{
case PAL_EC:
keyHandle = AndroidCryptoNative_NewEcKeyFromPublicKey(env, key);
keyHandle = AndroidCryptoNative_NewEcKeyFromKeys(env, key, NULL /*privateKey*/);
break;
case PAL_DSA:
keyHandle = AndroidCryptoNative_CreateKeyPair(env, key, NULL);
keyHandle = AndroidCryptoNative_CreateKeyPair(env, key, NULL /*privateKey*/);
break;
case PAL_RSA:
keyHandle = AndroidCryptoNative_NewRsaFromPublicKey(env, key);
keyHandle = AndroidCryptoNative_NewRsaFromKeys(env, key, NULL /*privateKey*/);
break;
default:
keyHandle = NULL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ enum
PAL_DSA = 0,
PAL_EC = 1,
PAL_RSA = 2,

PAL_UnknownAlgorithm = -1,
};
typedef uint32_t PAL_KeyAlgorithm;
typedef int32_t PAL_KeyAlgorithm;

/*
Gets an opaque handle for a certificate's public key
Expand Down
Loading

0 comments on commit eae9a1d

Please sign in to comment.