Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AndroidCrypto] Implement X509 chain building #49532

Merged
merged 22 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
28794a2
Basic chain building
elinor-fung Mar 10, 2021
10c92d9
Propagate error messages and set custom trust root certs
elinor-fung Mar 10, 2021
16751c4
Share x509 enums
elinor-fung Mar 11, 2021
ddb048d
Map failure reason to chain status when possible
elinor-fung Mar 11, 2021
14ac707
Update tests to reflect limited support on Android
elinor-fung Mar 11, 2021
aa47315
Handle revocation when newer APIs are available
elinor-fung Mar 12, 2021
ff5f4bd
Apply suggestions from code review
elinor-fung Mar 15, 2021
ecb6936
Move INIT_LOCALS, RELEASE_LOCALS, RELEASE_LOCALS_ENV macros to pal_jni
elinor-fung Mar 15, 2021
3191130
Apply suggestions from code review
elinor-fung Mar 17, 2021
1885f8e
Merge branch 'main' into chainPal-android
elinor-fung Mar 18, 2021
53a2fe4
Merge remote-tracking branch 'upstream/main' into chainPal-android
elinor-fung Mar 20, 2021
8a16ced
Stop throwing PNSE on verification/revocation flags that aren't respe…
elinor-fung Mar 20, 2021
f08663f
Update tests based on lack of AIA fetching support
elinor-fung Mar 20, 2021
ccfa398
Treat X509RevocationMode Offline as Online
elinor-fung Mar 21, 2021
a84f4ae
Make test revocation responder handle POST requests for OCSP
elinor-fung Mar 21, 2021
88db1e0
AddRef cert handles
elinor-fung Mar 22, 2021
9532108
Handle EndCertificateOnly revocation check with root-only chain
elinor-fung Mar 22, 2021
7d9f79b
Update DynamicRevocationTests for Android behaviour
elinor-fung Mar 22, 2021
d59e1c0
Merge branch 'main' into chainPal-android
elinor-fung Mar 22, 2021
8626ff6
Skip validation with revocation if without revocation failed
elinor-fung Mar 22, 2021
3628031
Update tests
elinor-fung Mar 22, 2021
d279986
Remove unnecessary dispose
elinor-fung Mar 22, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// 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.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

internal static partial class Interop
{
internal static partial class AndroidCrypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainCreateContext")]
internal static extern SafeX509ChainContextHandle X509ChainCreateContext(
SafeX509Handle cert,
IntPtr[] extraStore,
int extraStoreLen);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainDestroyContext")]
internal static extern void X509ChainDestroyContext(IntPtr ctx);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainBuild")]
[return: MarshalAs(UnmanagedType.U1)]
internal static extern bool X509ChainBuild(
SafeX509ChainContextHandle ctx,
long timeInMsFromUnixEpoch);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainGetCertificateCount")]
private static extern int X509ChainGetCertificateCount(SafeX509ChainContextHandle ctx);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainGetCertificates")]
private static extern int X509ChainGetCertificates(
SafeX509ChainContextHandle ctx,
IntPtr[] certs,
int certsLen);

internal static X509Certificate2[] X509ChainGetCertificates(SafeX509ChainContextHandle ctx)
{
int count = Interop.AndroidCrypto.X509ChainGetCertificateCount(ctx);
var certPtrs = new IntPtr[count];

int res = Interop.AndroidCrypto.X509ChainGetCertificates(ctx, certPtrs, certPtrs.Length);
if (res != SUCCESS)
throw new CryptographicException();

var certs = new X509Certificate2[certPtrs.Length];
for (int i = 0; i < certs.Length; i++)
{
certs[i] = new X509Certificate2(certPtrs[i]);
}

return certs;
}

[StructLayout(LayoutKind.Sequential)]
internal struct ValidationError
{
public IntPtr Message; // UTF-16 string
public int Index;
public int Status;
}

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainGetErrorCount")]
private static extern int X509ChainGetErrorCount(SafeX509ChainContextHandle ctx);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainGetErrors")]
private static unsafe extern int X509ChainGetErrors(
SafeX509ChainContextHandle ctx,
[Out] ValidationError[] errors,
int errorsLen);

internal static ValidationError[] X509ChainGetErrors(SafeX509ChainContextHandle ctx)
{
int count = Interop.AndroidCrypto.X509ChainGetErrorCount(ctx);
if (count == 0)
return Array.Empty<ValidationError>();

var errors = new ValidationError[count];
int res = Interop.AndroidCrypto.X509ChainGetErrors(ctx, errors, errors.Length);
if (res != SUCCESS)
throw new CryptographicException();

return errors;
}

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainSetCustomTrustStore")]
internal static extern int X509ChainSetCustomTrustStore(
SafeX509ChainContextHandle ctx,
IntPtr[] customTrustStore,
int customTrustStoreLen);

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainSupportsRevocationOptions")]
[return: MarshalAs(UnmanagedType.U1)]
internal static extern bool X509ChainSupportsRevocationOptions();

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_X509ChainValidate")]
internal static extern int X509ChainValidate(
SafeX509ChainContextHandle ctx,
X509RevocationMode revocationMode,
X509RevocationFlag revocationFlag);
}
}

namespace System.Security.Cryptography.X509Certificates
{
internal sealed class SafeX509ChainContextHandle : SafeHandle
{
public SafeX509ChainContextHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}

protected override bool ReleaseHandle()
{
Interop.AndroidCrypto.X509ChainDestroyContext(handle);
SetHandle(IntPtr.Zero);
return true;
}

public override bool IsInvalid => handle == IntPtr.Zero;
}
}
49 changes: 49 additions & 0 deletions src/libraries/Native/Unix/Common/pal_x509_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma once

// Matches managed X509ChainStatusFlags enum
enum
{
PAL_X509ChainNoError = 0,
PAL_X509ChainNotTimeValid = 0x00000001,
PAL_X509ChainNotTimeNested = 0x00000002,
PAL_X509ChainRevoked = 0x00000004,
PAL_X509ChainNotSignatureValid = 0x00000008,
PAL_X509ChainNotValidForUsage = 0x00000010,
PAL_X509ChainUntrustedRoot = 0x00000020,
PAL_X509ChainRevocationStatusUnknown = 0x00000040,
PAL_X509ChainCyclic = 0x00000080,
PAL_X509ChainInvalidExtension = 0x00000100,
PAL_X509ChainInvalidPolicyConstraints = 0x00000200,
PAL_X509ChainInvalidBasicConstraints = 0x00000400,
PAL_X509ChainInvalidNameConstraints = 0x00000800,
PAL_X509ChainHasNotSupportedNameConstraint = 0x00001000,
PAL_X509ChainHasNotDefinedNameConstraint = 0x00002000,
PAL_X509ChainHasNotPermittedNameConstraint = 0x00004000,
PAL_X509ChainHasExcludedNameConstraint = 0x00008000,
PAL_X509ChainPartialChain = 0x00010000,
PAL_X509ChainCtlNotTimeValid = 0x00020000,
PAL_X509ChainCtlNotSignatureValid = 0x00040000,
PAL_X509ChainCtlNotValidForUsage = 0x00080000,
PAL_X509ChainOfflineRevocation = 0x01000000,
PAL_X509ChainNoIssuanceChainPolicy = 0x02000000,
PAL_X509ChainExplicitDistrust = 0x04000000,
PAL_X509ChainHasNotSupportedCriticalExtension = 0x08000000,
PAL_X509ChainHasWeakSignature = 0x00100000,
};
typedef uint32_t PAL_X509ChainStatusFlags;

// Matches managed X509ContentType enum
enum
{
PAL_X509Unknown = 0,
PAL_Certificate = 1,
PAL_SerializedCert = 2,
PAL_Pkcs12 = 3,
PAL_SerializedStore = 4,
PAL_Pkcs7 = 5,
PAL_Authenticode = 6,
};
typedef uint32_t PAL_X509ContentType;
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_x509chain.c
)

add_library(System.Security.Cryptography.Native.Android
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@
#include "pal_signature.h"
#include "pal_bignum.h"

#define INIT_LOCALS(name, ...) \
enum { __VA_ARGS__, count_##name }; \
jobject name[count_##name] = { 0 } \

#define RELEASE_LOCALS_ENV(name, releaseFn) \
do { \
for (int i = 0; i < count_##name; ++i) \
{ \
releaseFn(env, name[i]); \
} \
} while(0)

int32_t AndroidCryptoNative_DsaGenerateKey(jobject* dsa, int32_t bits)
{
assert(dsa);
Expand Down Expand Up @@ -225,7 +213,7 @@ int32_t AndroidCryptoNative_GetDsaParameters(
assert(gLength);
assert(yLength);
assert(xLength);

JNIEnv* env = GetJNIEnv();

INIT_LOCALS(loc, algName, keyFactory, publicKey, publicKeySpec, privateKey, privateKeySpec);
Expand Down Expand Up @@ -282,7 +270,7 @@ int32_t AndroidCryptoNative_DsaKeyCreateByExplicitParameters(
assert(false);
return 0;
}

JNIEnv* env = GetJNIEnv();

INIT_LOCALS(bn, P, Q, G, Y, X);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@
#include "pal_jni.h"
#include "pal_utilities.h"


#define INIT_LOCALS(name, ...) \
enum { __VA_ARGS__, count_##name }; \
jobject name[count_##name] = { 0 } \

#define RELEASE_LOCALS_ENV(name, releaseFn) \
do { \
for (int i = 0; i < count_##name; ++i) \
{ \
releaseFn(env, name[i]); \
} \
} while(0)

int32_t AndroidCryptoNative_GetECKeyParameters(const EC_KEY* key,
int32_t includePrivate,
jobject* qx,
Expand Down
Loading