Skip to content

Commit

Permalink
Add COSE Service.
Browse files Browse the repository at this point in the history
  • Loading branch information
yspreen committed Apr 14, 2021
1 parent 2329b18 commit 5a632a3
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 77 deletions.
69 changes: 69 additions & 0 deletions PatientScannerDemo/COSE.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// COSE.swift
// PatientScannerDemo
//
// Created by Yannick Spreen on 4/14/21.
//

import Foundation
import SwiftCBOR
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]
else {
return false
}

let signedPayload: [UInt8] = CBOR.encode(
[
"Signature1",
array[0],
CBOR.byteString([]),
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 {
return false
}

struct TE : CustomStringConvertible {
var description: String
let kid : String
//let coord : Array()
}

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
}
}
107 changes: 30 additions & 77 deletions PatientScannerDemoTests/EHNTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SwiftCBOR

var barcode = "HC1NCFY70R30FFWTWGSLKC 4O992$V M63TMF2V*D9LPC.3EHPCGEC27B72VF/347O4-M6Y9M6FOYG4ILDEI8GR3ZI$15MABL:E9CVBGEEWRMLE C39S0/ANZ52T82Z-73D63P1U 1$PKC 72H2XX09WDH889V5"

let trust_json = """
let trustJson = """
[
{
\"kid\" : \"DEFBBA3378B322F5\",
Expand All @@ -33,10 +33,8 @@ let trust_json = """


class EHNTests: XCTestCase {

func test_cose() throws {
let COSE_TAG = UInt64(18)
let COSE_PHDR_SIG = CBOR.unsignedInt(1)
let COSE_PHDR_KID = CBOR.unsignedInt(4)

// Remove HC1 header if any
Expand All @@ -47,108 +45,63 @@ class EHNTests: XCTestCase {
guard
let compressed = try? barcode.fromBase45()
else {
assert(false)
XCTAssert(false)
return
}

let data = decompress(compressed)
let decoder = SwiftCBOR.CBORDecoder(input: data.uint)

guard
let cose = try? decoder.decodeItem(),
case let CBOR.tagged(tag, cborElement) = cose,
let cbor = try? decoder.decodeItem(),
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
else {
assert(false)
XCTAssert(false)
return
}
var kid: [UInt8] = []
let sig = protectedMap[COSE_PHDR_SIG]!

print("SIG: ", sig)
if case let CBOR.byteString(k) = protectedMap[COSE_PHDR_KID] ?? .null {
kid = k
} else {
assert(false)
guard case let CBOR.byteString(kid) = protectedMap[COSE_PHDR_KID] ?? .null else {
XCTAssert(false)
return
}

print("Signature: ", signature)
print("Payload: ", payload)
print("KID: ", kid)

let externalData = CBOR.byteString([])
let signed_payload: [UInt8] = CBOR.encode(
[
"Signature1",
array[0],
externalData,
array[2]
]
)
let d = Data(bytes: signed_payload, count: signed_payload.count)
print("Signing: ", d.base64EncodedString())
let digest = SHA256.hash(data: signed_payload)
print("Digest: ", digest)

let signatureForData = try! P256.Signing.ECDSASignature(rawRepresentation: signature)

// use KID to find the right X,Y coordinates from the JSON
//
struct TE : CustomStringConvertible {
var description: String
let kid : String
//let coord : Array()
guard
let trustData = trustJson.data(using: .utf8),
let trustSerialization = try? JSONSerialization.jsonObject(with: trustData, options: []),
let trust = trustSerialization as? [[String: Any]]
else {
XCTAssert(false)
return
}
var x: [UInt8] = []
var y: [UInt8] = []

let _ = unprotected // unused

if let trust = try? JSONSerialization.jsonObject(with: trust_json.data(using: .utf8)!, options: []) as? [[String: Any]] {
for case let elem: Dictionary in trust {
if kid == Data(hexString: elem["kid"] as! String)?.uint {
print("We know this KID - check if this sig works...")
x = Data(hexString: ((elem["coord"] as! Array<Any>)[0] as? String) ?? "")?.uint ?? []
y = Data(hexString: ((elem["coord"] as! Array<Any>)[1] as? String) ?? "")?.uint ?? []

var rawk: [UInt8] = [04]
rawk.append(contentsOf: x)
rawk.append(contentsOf: y)
XCTAssert(rawk.count == 32+32+1)

if
let publicKey = try? P256.Signing.PublicKey(x963Representation: rawk),
publicKey.isValidSignature(signatureForData, for: digest)
{
print("All is WELL !")

print("Payload (decoded)")
print(array[2])
return
}
print("- sig failed - which is OK - we may have more matching KIDS --")
for case let elem: Dictionary in trust {
if
kid == Data(hexString: elem["kid"] as! String)?.uint,
let x = (elem["coord"] as? Array<Any>)?[0] as? String,
let y = (elem["coord"] as? Array<Any>)?[1] as? String
{
print("We know this KID - check if this sig works...")
if COSE.verify(cbor, with: x, and: y) {
print("All is well! Payload: ", payload)
return
}
print("Nope - all failed - sadness all around")
assert(false)
print("- sig failed - which is OK - we may have more matching KIDS --")
}
}
print("Nope - all failed - sadness all around")
XCTAssert(false)
}
}

/**

Produces:

All is WELL !
Payload (decoded)
byteString([161, 99, 102, 111, 111, 99, 98, 97, 114])

All is well! Payload: map([SwiftCBOR.CBOR.utf8String("foo"): SwiftCBOR.CBOR.utf8String("bar")])

*/

0 comments on commit 5a632a3

Please sign in to comment.