Signing using a smart card is a common operation. This guide will show you how to sign some data. In order to sign data using a smart card, you will need a few prerequisites:
- the credential you are going to use for the signature, which is a certificate found inside the smart card
- the pin of the smart card associated with the certificate
The first part is about choosing the credential. This step can be simple if there is only one certificate inside the smart card. But in general, a smart card can contain more than just one certificate. We made the following example get all the certificate inside the smart card. After this step, you can display the certificates and let the user choose the one.
func getCredential(reader: Reader, completion_handler: @escaping ([Certificate]?) -> Void) -> Void {
reader.connect { token, error in
if let token = token {
token.getObjects { objects, error in
if let objects = objects {
var readers: [Certificate] = []
for object in objects {
if object.getType() == .certificate {
readers.append( object as! Certificate)
}
}
completion_handler(readers)
}
else {
print("Could not get objects : " + error!.localizedDescription);
token.disconnect(completionHandler: { error in
if let error = error {
print("Error while disconnectin : " + error.localizedDescription);
}
completion_handler(nil);
})
}
}
}
else {
print("Could not connect : " + error!.localizedDescription);
completion_handler(nil);
}
}
}
After getting the credential to use for signing, you need to ask the user to give you his pin, in order to login. be careful to choose the right PIN. Some smart card have multiple pin inside them. And you should ask for the right pin.
Using the pin, we can log in inside the smart card. Get all the private key. Find the Private key that match the credential selected earlier. And finally, sign our data with the private key.
The following function shows how to handle the signature after getting the pin and the credential.
func signData(token: Token, credential: Certificate, dataToSign: Data, pin: String, completionHandler:@escaping (_ : Data?) -> Void) -> Void {
// first we get the right Pin object in order to login.
// the pin index is extracted from the certificate since we know the private key has the same pin as the certificate.
let pinIndex = credential.getPinNumber()
token.pins()[pinIndex].login(value: pin, completionHandler: { error in
if let error = error {
print("Could not login : " + error.localizedDescription)
completionHandler(nil)
}
else {
// if login is succefull you should try to get the token object
// now the prvate key should appear.
token.getObjects { objects, error in
if let objects = objects {
for object in objects {
// we need to find and object that is a private key
// we also need that this private key is associated with the certificate
// the private key and the certificate should have the same CKID. this is how we find the right private key among all the private key inside the card.
if (object.getType() == .privateKey && (object.getCkId() == credential.getCkId())) {
let privatekey = object as! PrivateKey
// Finaly we can sign our datas
privatekey.hashAndSign(data: dataToSign, algorithm: "sha256") { signature, error in
if let signature = signature {
completionHandler(signature);
}
else {
print("Could not sign the datas : " + error!.localizedDescription)
completionHandler(nil)
}
}
}
}
}
else {
print("Could not get objects : " + error!.localizedDescription)
completionHandler(nil)
}
}
}
})
}