-
Notifications
You must be signed in to change notification settings - Fork 86
/
_27_Pkcs11UriUtilsTest.cs
131 lines (110 loc) · 5.69 KB
/
_27_Pkcs11UriUtilsTest.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
* Copyright 2012-2021 The Pkcs11Interop Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Written for the Pkcs11Interop project by:
* Jaroslav IMRICH <jimrich@jimrich.sk>
*/
using System;
using System.Collections.Generic;
using Net.Pkcs11Interop.Common;
using Net.Pkcs11Interop.HighLevelAPI;
using NUnit.Framework;
// Note: Code in this file is maintained manually.
namespace Net.Pkcs11Interop.Tests.HighLevelAPI
{
/// <summary>
/// Pkcs11UriUtils tests
/// </summary>
[TestFixture()]
public partial class _27_Pkcs11UriUtilsTest
{
/// <summary>
/// Demonstration of PKCS#11 URI usage in a signature creation application
/// </summary>
[Test()]
public void _01_Pkcs11UriInSignatureCreationApplication()
{
// PKCS#11 URI can be acquired i.e. from configuration file as a simple string...
string uri = @"<pkcs11:serial=7BFF2737350B262C;
type=private;
object=John%20Doe
?module-path=pkcs11.dll&
pin-value=11111111>";
Assert.IsNotNull(uri);
// ...or it can be easily constructed with Pkcs11UriBuilder
Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
pkcs11UriBuilder.Serial = "7BFF2737350B262C";
pkcs11UriBuilder.Type = CKO.CKO_PRIVATE_KEY;
pkcs11UriBuilder.Object = "John Doe";
pkcs11UriBuilder.ModulePath = "pkcs11.dll";
pkcs11UriBuilder.PinValue = "11111111";
uri = pkcs11UriBuilder.ToString();
Assert.IsNotNull(uri);
// Warning: Please note that PIN stored in PKCS#11 URI can pose a security risk and therefore other options
// should be carefully considered. For example an application may ask for a PIN with a GUI dialog etc.
// Use PKCS#11 URI acquired from Settings class to identify private key in signature creation method
byte[] signature = SignData(ConvertUtils.Utf8StringToBytes("Hello world"), Settings.PrivateKeyUri);
// Do something interesting with the signature
Assert.IsNotNull(signature);
}
/// <summary>
/// Creates the PKCS#1 v1.5 RSA signature with SHA-1 mechanism
/// </summary>
/// <param name="data">Data that should be signed</param>
/// <param name="uri">PKCS#11 URI identifying PKCS#11 library, token and private key</param>
/// <returns>PKCS#1 v1.5 RSA signature</returns>
private byte[] SignData(byte[] data, string uri)
{
// Verify input parameters
if (data == null)
throw new ArgumentNullException("data");
if (string.IsNullOrEmpty(uri))
throw new ArgumentNullException("uri");
// Parse PKCS#11 URI
Pkcs11Uri pkcs11Uri = new Pkcs11Uri(uri);
// Verify that URI contains all information required to perform this operation
if (pkcs11Uri.ModulePath == null)
throw new Exception("PKCS#11 URI does not specify PKCS#11 library");
if (pkcs11Uri.PinValue == null)
throw new Exception("PKCS#11 URI does not specify PIN");
if (!pkcs11Uri.DefinesObject || pkcs11Uri.Type != CKO.CKO_PRIVATE_KEY)
throw new Exception("PKCS#11 URI does not specify private key");
// Load and initialize PKCS#11 library specified by URI
using (IPkcs11Library pkcs11Library = Settings.Factories.Pkcs11LibraryFactory.LoadPkcs11Library(Settings.Factories, pkcs11Uri.ModulePath, AppType.MultiThreaded))
{
// Obtain a list of all slots with tokens that match URI
List<ISlot> slots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11Uri, pkcs11Library, SlotsType.WithTokenPresent);
if ((slots == null) || (slots.Count == 0))
throw new Exception("None of the slots matches PKCS#11 URI");
// Open read only session with first token that matches URI
using (ISession session = slots[0].OpenSession(SessionType.ReadOnly))
{
// Login as normal user with PIN acquired from URI
session.Login(CKU.CKU_USER, pkcs11Uri.PinValue);
// Get list of object attributes for the private key specified by URI
List<IObjectAttribute> searchTemplate = Pkcs11UriUtils.GetObjectAttributes(pkcs11Uri, session.Factories.ObjectAttributeFactory);
// Find private key specified by URI
List<IObjectHandle> foundObjects = session.FindAllObjects(searchTemplate);
if ((foundObjects == null) || (foundObjects.Count == 0))
throw new Exception("None of the private keys match PKCS#11 URI");
// Create signature with the private key specified by URI
using (IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_SHA1_RSA_PKCS))
return session.Sign(mechanism, foundObjects[0], data);
}
}
}
}
}