diff --git a/PatientScannerDemo.xcodeproj/project.pbxproj b/PatientScannerDemo.xcodeproj/project.pbxproj index c0ccf8b..619ec16 100644 --- a/PatientScannerDemo.xcodeproj/project.pbxproj +++ b/PatientScannerDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + CE3CC93C2628A7820079FB78 /* ASN1.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE3CC93B2628A7820079FB78 /* ASN1.swift */; }; CE7DE7FA2625EF18007E6694 /* SwiftCBOR in Frameworks */ = {isa = PBXBuildFile; productRef = CE7DE7F92625EF18007E6694 /* SwiftCBOR */; }; CEA6D6EC261F8D2700715333 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA6D6EB261F8D2700715333 /* AppDelegate.swift */; }; CEA6D6EE261F8D2700715333 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA6D6ED261F8D2700715333 /* SceneDelegate.swift */; }; @@ -44,6 +45,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + CE3CC93B2628A7820079FB78 /* ASN1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASN1.swift; sourceTree = ""; }; CEA6D6E8261F8D2700715333 /* PatientScannerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PatientScannerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; CEA6D6EB261F8D2700715333 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; CEA6D6ED261F8D2700715333 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -129,6 +131,7 @@ CEA6D6F6261F8D2900715333 /* LaunchScreen.storyboard */, CEA6D6F9261F8D2900715333 /* Info.plist */, CEFAD86C2625F164009AFEF9 /* EC256.swift */, + CE3CC93B2628A7820079FB78 /* ASN1.swift */, CEFAD87926271414009AFEF9 /* COSE.swift */, CEFAD88626271B9A009AFEF9 /* Data+hexString.swift */, ); @@ -294,6 +297,7 @@ CEC2C4C32625ED030056E406 /* JWK.swift in Sources */, CEC2C4C42625ED030056E406 /* Base45.swift in Sources */, CEA6D6F0261F8D2700715333 /* ViewController.swift in Sources */, + CE3CC93C2628A7820079FB78 /* ASN1.swift in Sources */, CEFAD87A26271414009AFEF9 /* COSE.swift in Sources */, CEFAD86D2625F164009AFEF9 /* EC256.swift in Sources */, CEA6D6EC261F8D2700715333 /* AppDelegate.swift in Sources */, diff --git a/PatientScannerDemo/Asn1Encoder.swift b/PatientScannerDemo/ASN1.swift similarity index 79% rename from PatientScannerDemo/Asn1Encoder.swift rename to PatientScannerDemo/ASN1.swift index 4085186..badc02d 100644 --- a/PatientScannerDemo/Asn1Encoder.swift +++ b/PatientScannerDemo/ASN1.swift @@ -7,19 +7,16 @@ import Foundation -public class Asn1Encoder { - - public init() {} - +public class ASN1 { // 32 for ES256 - public func convertRawSignatureIntoAsn1(_ data: Data, _ digestLengthInBytes: Int = 32) -> Data { + public static func signature(from data: Data, _ digestLengthInBytes: Int = 32) -> Data { let sigR = encodeIntegerToAsn1(data.prefix(data.count - digestLengthInBytes)) let sigS = encodeIntegerToAsn1(data.suffix(digestLengthInBytes)) let tagSequence: UInt8 = 0x30 return Data([tagSequence] + [UInt8(sigR.count + sigS.count)] + sigR + sigS) } - private func encodeIntegerToAsn1(_ data: Data) -> Data { + private static func encodeIntegerToAsn1(_ data: Data) -> Data { let firstBitIsSet: UInt8 = 0x80 // would be decoded as a negative number let tagInteger: UInt8 = 0x02 if (data.first! >= firstBitIsSet) { diff --git a/PatientScannerDemo/COSE.swift b/PatientScannerDemo/COSE.swift index 66ddd81..3afe71b 100644 --- a/PatientScannerDemo/COSE.swift +++ b/PatientScannerDemo/COSE.swift @@ -7,25 +7,17 @@ import Foundation import SwiftCBOR -import CryptoKit +//import CryptoKit struct COSE { public static func verify(_ cbor: CBOR, with xHex: String, and yHex: String) -> Bool { let COSE_TAG = UInt64(18) - let COSE_PHDR_SIG = CBOR.unsignedInt(1) guard case let CBOR.tagged(tag, cborElement) = cbor, tag.rawValue == COSE_TAG, // SIGN1 case let CBOR.array(array) = cborElement, - case let CBOR.byteString(protectedBytes) = array[0], - case let CBOR.map(unprotected) = array[1], - case let CBOR.byteString(payloadBytes) = array[2], - case let CBOR.byteString(signature) = array[3], - let protected = try? CBOR.decode(protectedBytes), - let payload = try? CBOR.decode(payloadBytes), - case let CBOR.map(protectedMap) = protected, - let sig = protectedMap[COSE_PHDR_SIG] + case let CBOR.byteString(signature) = array[3] else { return false } @@ -38,26 +30,12 @@ struct COSE { array[2] ] ) - let d = Data(bytes: signedPayload, count: signedPayload.count) - let digest = SHA256.hash(data: signedPayload) - guard - let signatureForData = try? P256.Signing.ECDSASignature(rawRepresentation: signature) - else { + let d = Data(signedPayload)//Data(bytes: signedPayload, count: signedPayload.count) +// let digest = SHA256.hash(data: signedPayload) + let s = Data(signature)//Data(bytes: signature, count: signature.count) + guard let key = JWK.ecFrom(x: xHex, y: yHex) else { return false } - - let x = Data(hexString: xHex)?.uint ?? [] - let y = Data(hexString: yHex)?.uint ?? [] - let rawk: [UInt8] = [04] + x + y - let _ = (unprotected, sig, d, payload) // unused - - if - rawk.count == 32+32+1, - let publicKey = try? P256.Signing.PublicKey(x963Representation: rawk), - publicKey.isValidSignature(signatureForData, for: digest) - { - return true - } - return false + return EC256.verify(signature: s, for: d, with: key) } } diff --git a/PatientScannerDemo/EC256.swift b/PatientScannerDemo/EC256.swift index bb3d66b..55e6ece 100644 --- a/PatientScannerDemo/EC256.swift +++ b/PatientScannerDemo/EC256.swift @@ -11,28 +11,27 @@ import Foundation struct EC256 { public static func verify(signature: Data, for data: Data, with publicKey: SecKey) -> Bool { - var error: Unmanaged? - let targetsSignedData = data as NSData - guard SecKeyIsAlgorithmSupported(publicKey, .verify, .ecdsaSignatureMessageX962SHA256) else { print("Pubkey not supported.") return false } + let sig = ASN1.signature(from: signature) + // verify signature - if SecKeyVerifySignature( - publicKey, - SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256, - targetsSignedData, - signature as NSData, - &error - ) { - return true - } - else { - print(error?.takeUnretainedValue().localizedDescription ?? "Something went wrong") - return false + var error: Unmanaged? + let result = SecKeyVerifySignature( + publicKey, + .ecdsaSignatureMessageX962SHA256, + data as NSData, + sig as NSData, + &error + ) + if let err = error?.takeUnretainedValue().localizedDescription { + print(err) } + error?.release() + + return result } } - diff --git a/PatientScannerDemo/JWK.swift b/PatientScannerDemo/JWK.swift index 8e4ee92..fb7adba 100644 --- a/PatientScannerDemo/JWK.swift +++ b/PatientScannerDemo/JWK.swift @@ -10,42 +10,50 @@ import Foundation struct JWK { - public static func from(x: String, y: String) -> SecKey? { - var xStr = x // Base64 Formatted data - var yStr = y + public static func ecFrom(x: String, y: String) -> SecKey? { + var xBytes: Data? + var yBytes: Data? + if (x + y).count == 128 { + xBytes = Data(hexString: x) + yBytes = Data(hexString: y) + } else { + var xStr = x // Base64 Formatted data + var yStr = y - xStr = xStr.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") - while xStr.count % 4 != 0 { - xStr.append("=") + xStr = xStr.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") + while xStr.count % 4 != 0 { + xStr.append("=") + } + yStr = yStr.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") + while yStr.count % 4 != 0 { + yStr.append("=") + } + xBytes = Data(base64Encoded: xStr) + yBytes = Data(base64Encoded: yStr) } - yStr = yStr.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") - while yStr.count % 4 != 0 { - yStr.append("=") - } - guard - let xBytes = Data(base64Encoded: xStr), - let yBytes = Data(base64Encoded: yStr) - else { return nil } - // Now this bytes we have to append such that [0x04 , /* xBytes */, /* yBytes */, /* dBytes */] + // Now this bytes we have to append such that [0x04 , /* xBytes */, /* yBytes */] // Initial byte for uncompressed y as Key. - let keyData = NSMutableData.init(bytes: [0x04], length: [0x04].count) - keyData.append(xBytes) - keyData.append(yBytes) + let keyData = NSMutableData.init(bytes: [0x04], length: 1) + keyData.append(xBytes ?? Data()) + keyData.append(yBytes ?? Data()) let attributes: [String: Any] = [ - kSecAttrKeyType as String: kSecAttrKeyTypeEC, - kSecAttrKeyClass as String: kSecAttrKeyClassPublic, - kSecAttrKeySizeInBits as String: 256, - kSecAttrIsPermanent as String: false + String(kSecAttrKeyType): kSecAttrKeyTypeEC, + String(kSecAttrKeyClass): kSecAttrKeyClassPublic, + String(kSecAttrKeySizeInBits): 256, + String(kSecAttrIsPermanent): false ] var error: Unmanaged? + let keyReference = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, &error) + let errorString = error?.takeUnretainedValue().localizedDescription ?? "Something went wrong" + error?.release() guard - let keyReference = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, &error) + let key = keyReference else { - print(error?.takeUnretainedValue().localizedDescription ?? "Something went wrong") + print(errorString) return nil } - return keyReference + return key } } diff --git a/PatientScannerDemo/ViewController.swift b/PatientScannerDemo/ViewController.swift index e6422c1..8306eab 100644 --- a/PatientScannerDemo/ViewController.swift +++ b/PatientScannerDemo/ViewController.swift @@ -183,7 +183,7 @@ extension ViewController { guard let x = keyJWK["x"] as? String, let y = keyJWK["y"] as? String, - let pubKey = JWK.from(x: x, y: y) + let pubKey = JWK.ecFrom(x: x, y: y) else { return } print(EC256.verify(signature: Data(signature), for: Data(payloadBytes), with: pubKey)) diff --git a/PatientScannerDemoTests/EHNTests.swift b/PatientScannerDemoTests/EHNTests.swift index 92b07f7..e275320 100644 --- a/PatientScannerDemoTests/EHNTests.swift +++ b/PatientScannerDemoTests/EHNTests.swift @@ -10,30 +10,29 @@ import XCTest import CryptoKit import SwiftCBOR -var barcode = "HC1NCFY70R30FFWTWGSLKC 4O992$V M63TMF2V*D9LPC.3EHPCGEC27B72VF/347O4-M6Y9M6FOYG4ILDEI8GR3ZI$15MABL:E9CVBGEEWRMLE C39S0/ANZ52T82Z-73D63P1U 1$PKC 72H2XX09WDH889V5" - -let trustJson = """ -[ - { - \"kid\" : \"DEFBBA3378B322F5\", - \"coord\" : [ - \"230ca0433313f4ef14ec0ab0477b241781d135ee09369507fcf44ca988ed09d6\", - \"bf1bfe3d2bda606c841242b59c568d00e5c8dd114d223b2f5036d8c5bc68bf5d\" - ] - }, - { - \"kid\" : \"FFFBBA3378B322F5\", - \"coord\" : [ - \"9999a0433313f4ef14ec0ab0477b241781d135ee09369507fcf44ca988ed09d6\", - \"9999fe3d2bda606c841242b59c568d00e5c8dd114d223b2f5036d8c5bc68bf5d\" - ] - } -] -""" - - class EHNTests: XCTestCase { func test_cose() throws { + + var barcode = "HC1NCFY70R30FFWTWGSLKC 4O992$V M63TMF2V*D9LPC.3EHPCGEC27B72VF/347O4-M6Y9M6FOYG4ILDEI8GR3ZI$15MABL:E9CVBGEEWRMLE C39S0/ANZ52T82Z-73D63P1U 1$PKC 72H2XX09WDH889V5" + + let trustJson = """ + [ + { + \"kid\" : \"DEFBBA3378B322F5\", + \"coord\" : [ + \"230ca0433313f4ef14ec0ab0477b241781d135ee09369507fcf44ca988ed09d6\", + \"bf1bfe3d2bda606c841242b59c568d00e5c8dd114d223b2f5036d8c5bc68bf5d\" + ] + }, + { + \"kid\" : \"FFFBBA3378B322F5\", + \"coord\" : [ + \"9999a0433313f4ef14ec0ab0477b241781d135ee09369507fcf44ca988ed09d6\", + \"9999fe3d2bda606c841242b59c568d00e5c8dd114d223b2f5036d8c5bc68bf5d\" + ] + } + ] + """ let COSE_TAG = UInt64(18) let COSE_PHDR_KID = CBOR.unsignedInt(4)