Skip to content

Commit fc790ab

Browse files
committed
Merge pull request dotnet/corefx#2912 from bartonjs/unix_pkcs7
Add support for importing PKCS7 files as X509Certificate2Collections. Commit migrated from dotnet/corefx@36969f1
2 parents 1faf16e + 294c9d8 commit fc790ab

File tree

16 files changed

+1450
-212
lines changed

16 files changed

+1450
-212
lines changed

src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Crypto.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,23 @@ internal static partial class Crypto
6666
[DllImport(Libraries.CryptoNative)]
6767
internal static extern int GetX509StackFieldCount(SafeX509StackHandle stack);
6868

69+
[DllImport(Libraries.CryptoNative)]
70+
internal static extern int GetX509StackFieldCount(SafeSharedX509StackHandle stack);
71+
6972
/// <summary>
7073
/// Gets a pointer to a certificate within a STACK_OF(X509). This pointer will later
7174
/// be freed, so it should be cloned via new X509Certificate2(IntPtr)
7275
/// </summary>
7376
[DllImport(Libraries.CryptoNative)]
7477
internal static extern IntPtr GetX509StackField(SafeX509StackHandle stack, int loc);
7578

79+
/// <summary>
80+
/// Gets a pointer to a certificate within a STACK_OF(X509). This pointer will later
81+
/// be freed, so it should be cloned via new X509Certificate2(IntPtr)
82+
/// </summary>
83+
[DllImport(Libraries.CryptoNative)]
84+
internal static extern IntPtr GetX509StackField(SafeSharedX509StackHandle stack, int loc);
85+
7686
[DllImport(Libraries.CryptoNative)]
7787
[return: MarshalAs(UnmanagedType.Bool)]
7888
internal static extern bool PushX509StackField(SafeX509StackHandle stack, SafeX509Handle x509);
@@ -86,6 +96,9 @@ internal static partial class Crypto
8696
[DllImport(Libraries.CryptoNative)]
8797
internal static extern int UpRefEvpPkey(SafeEvpPkeyHandle handle);
8898

99+
[DllImport(Libraries.CryptoNative)]
100+
private static extern int GetPkcs7Certificates(SafePkcs7Handle p7, out SafeSharedX509StackHandle certs);
101+
89102
[DllImport(Libraries.CryptoNative)]
90103
private static extern int SetX509ChainVerifyTime(
91104
SafeX509StoreCtxHandle ctx,
@@ -141,6 +154,27 @@ internal static void SetX509ChainVerifyTime(SafeX509StoreCtxHandle ctx, DateTime
141154
}
142155
}
143156

157+
internal static SafeSharedX509StackHandle GetPkcs7Certificates(SafePkcs7Handle p7)
158+
{
159+
if (p7 == null || p7.IsInvalid)
160+
{
161+
return SafeSharedX509StackHandle.InvalidHandle;
162+
}
163+
164+
SafeSharedX509StackHandle certs;
165+
int result = GetPkcs7Certificates(p7, out certs);
166+
167+
if (result != 1)
168+
{
169+
throw Interop.libcrypto.CreateOpenSslCryptographicException();
170+
}
171+
172+
// Track the parent relationship for the interior pointer so lifetime is well-managed.
173+
certs.SetParent(p7);
174+
175+
return certs;
176+
}
177+
144178
private static byte[] GetDynamicBuffer<THandle>(NegativeSizeReadMethod<THandle> method, THandle handle)
145179
{
146180
int negativeSize = method(handle, null, 0);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
7+
using Microsoft.Win32.SafeHandles;
8+
9+
internal static partial class Interop
10+
{
11+
internal static partial class libcrypto
12+
{
13+
[DllImport(Libraries.LibCrypto)]
14+
internal static extern SafePkcs7Handle PEM_read_bio_PKCS7(SafeBioHandle bp, IntPtr xZero, IntPtr cbZero, IntPtr uZero);
15+
16+
[DllImport(Libraries.LibCrypto)]
17+
internal static unsafe extern SafePkcs7Handle d2i_PKCS7(IntPtr zero, byte** ppin, int len);
18+
19+
[DllImport(Libraries.LibCrypto)]
20+
internal static extern SafePkcs7Handle d2i_PKCS7_bio(SafeBioHandle bp, IntPtr pp7Zero);
21+
22+
[DllImport(Libraries.LibCrypto)]
23+
internal static extern void PKCS7_free(IntPtr p12);
24+
}
25+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
7+
namespace Microsoft.Win32.SafeHandles
8+
{
9+
internal sealed class SafePkcs7Handle : SafeHandle
10+
{
11+
private SafePkcs7Handle() :
12+
base(IntPtr.Zero, ownsHandle: true)
13+
{
14+
}
15+
16+
protected override bool ReleaseHandle()
17+
{
18+
Interop.libcrypto.PKCS7_free(handle);
19+
SetHandle(IntPtr.Zero);
20+
return true;
21+
}
22+
23+
public override bool IsInvalid
24+
{
25+
get { return handle == IntPtr.Zero; }
26+
}
27+
}
28+
}

src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeX509Handles.Unix.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5+
using System.Diagnostics;
56
using System.Security;
67
using System.Runtime.InteropServices;
78

@@ -92,4 +93,53 @@ public override bool IsInvalid
9293
get { return handle == IntPtr.Zero; }
9394
}
9495
}
96+
97+
/// <summary>
98+
/// Represents access to a STACK_OF(X509)* which is a member of a structure tracked
99+
/// by another SafeHandle.
100+
/// </summary>
101+
[SecurityCritical]
102+
internal sealed class SafeSharedX509StackHandle : SafeHandle
103+
{
104+
internal static readonly SafeSharedX509StackHandle InvalidHandle = new SafeSharedX509StackHandle();
105+
private SafeHandle _parent;
106+
107+
private SafeSharedX509StackHandle() :
108+
base(IntPtr.Zero, ownsHandle: true)
109+
{
110+
}
111+
112+
protected override bool ReleaseHandle()
113+
{
114+
SafeHandle parent = _parent;
115+
116+
if (parent != null)
117+
{
118+
parent.DangerousRelease();
119+
}
120+
121+
_parent = null;
122+
SetHandle(IntPtr.Zero);
123+
return true;
124+
}
125+
126+
public override bool IsInvalid
127+
{
128+
get
129+
{
130+
// If handle is 0, we're invalid.
131+
// If we have a _parent and they're invalid, we're invalid.
132+
return handle == IntPtr.Zero || (_parent != null && _parent.IsInvalid);
133+
}
134+
}
135+
136+
internal void SetParent(SafeHandle parent)
137+
{
138+
bool addedRef = false;
139+
parent.DangerousAddRef(ref addedRef);
140+
Debug.Assert(addedRef);
141+
142+
_parent = parent;
143+
}
144+
}
95145
}

src/libraries/Native/System.Security.Cryptography.Native/openssl.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,41 @@ UpRefEvpPkey(
918918
return CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
919919
}
920920

921+
/*
922+
Function:
923+
GetPkcs7Certificates
924+
925+
Used by System.Security.Cryptography.X509Certificates' CertificatePal when
926+
reading the contents of a PKCS#7 file or blob.
927+
928+
Return values:
929+
0 on NULL inputs, or a PKCS#7 file whose layout is not understood
930+
1 when the file format is understood, and *certs is assigned to the
931+
certificate contents of the structure.
932+
*/
933+
int
934+
GetPkcs7Certificates(
935+
PKCS7* p7,
936+
STACK_OF(X509)** certs)
937+
{
938+
if (!p7 || !certs)
939+
{
940+
return 0;
941+
}
942+
943+
switch (OBJ_obj2nid(p7->type))
944+
{
945+
case NID_pkcs7_signed:
946+
*certs = p7->d.sign->cert;
947+
return 1;
948+
case NID_pkcs7_signedAndEnveloped:
949+
*certs = p7->d.signed_and_enveloped->cert;
950+
return 1;
951+
}
952+
953+
return 0;
954+
}
955+
921956
// Lock used to make sure EnsureopenSslInitialized itself is thread safe
922957
static pthread_mutex_t g_initLock = PTHREAD_MUTEX_INITIALIZER;
923958

0 commit comments

Comments
 (0)