Pkcs11Interop  4.1.1
* Copyright 2012-2019 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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
* Written for the Pkcs11Interop project by:
* Jaroslav IMRICH <>
using NUnit.Framework;
using System;
using System.Collections.Generic;
namespace Net.Pkcs11Interop.Tests.HighLevelAPI
/// <summary>
/// Pkcs11UriUtils tests
/// </summary>
public partial class _27_Pkcs11UriUtilsTest
/// <summary>
/// Demonstration of PKCS#11 URI usage in a signature creation application
/// </summary>
public void _01_Pkcs11UriInSignatureCreationApplication()
// PKCS#11 URI can be acquired i.e. from configuration file as a simple string...
string uri = @"<pkcs11:serial=7BFF2737350B262C;
// ...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();
// 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
/// <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 (Pkcs11 pkcs11 = new Pkcs11(pkcs11Uri.ModulePath, AppType.MultiThreaded))
// Obtain a list of all slots with tokens that match URI
List<Slot> slots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11Uri, pkcs11, true);
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 (Session 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<ObjectAttribute> searchTemplate = null;
Pkcs11UriUtils.GetObjectAttributes(pkcs11Uri, out searchTemplate);
// Find private key specified by URI
List<ObjectHandle> 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
return session.Sign(new Mechanism(CKM.CKM_SHA1_RSA_PKCS), foundObjects[0], data);