Skip to content

Commit

Permalink
Merge branch 'EWC-consortium:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
josmilan authored Oct 10, 2024
2 parents fe3bcbb + 889c97d commit dd91288
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// File.swift
//
//
// Created by oem on 10/10/24.
//

import Foundation

class ProcessEbsiJWKFromKID {

static func processJWKforEBSI(did: String?) async -> [String: Any]{
guard let did = did else { return [:]}
let ebsiEndPoint = "https://api-conformance.ebsi.eu/did-registry/v5/identifiers/\(did)"
let pilotEndpoint = "https://api-pilot.ebsi.eu/did-registry/v5/identifiers/\(did)"

do {
guard let url = URL(string: ebsiEndPoint) else { return [:] }
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse else { return [:] }

if httpResponse.statusCode == 200 {
// Process the response from the first URL
return try processPublicKeyFromJWKList(data)
} else {
// Call the fallback URL if the status is not 200
return try await fetchJWKListFromUrl(pilotEndpoint)
}
} catch {
print("Error fetching from primary URL: \(error)")
}
return [:]
}

private static func processPublicKeyFromJWKList(_ data: Data) throws -> [String: Any] {
guard let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let verificationMethods = jsonObject["verificationMethod"] as? [[String: Any]] else { return [:] }

for method in verificationMethods {
if let publicKeyJwk = method["publicKeyJwk"] as? [String: Any],
let crv = publicKeyJwk["crv"] as? String, crv == "P-256" {
return publicKeyJwk
}
}
return [:]
}

private static func fetchJWKListFromUrl(_ fallbackURL: String) async throws -> [String: Any] {
guard let url = URL(string: fallbackURL) else { return [:] }
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return [:] }

return try processPublicKeyFromJWKList(data)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// File.swift
//
//
// Created by oem on 10/10/24.
//

import Foundation

class ProcessJWKFromJwksUri {

static func processJWKFromJwksURI2(kid: String?, jwksURI: String?) async -> [String: Any] {
guard let jwksURI = jwksURI else {return [:]}
return await fetchJwkData(kid: kid, jwksUri: jwksURI)
}

static func fetchJwkData(kid: String?, jwksUri: String)async -> [String: Any] {
guard let url = URL(string: jwksUri) else {
return [:]
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return [:]}
guard let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let keys = jsonObject["keys"] as? [[String: Any]] else { return [:]}

var jwkKey: [String: Any]? = keys.first { $0["use"] as? String == "sig" }

if jwkKey == nil, let kid = kid {
jwkKey = keys.first { $0["kid"] as? String == kid }
}
return jwkKey ?? [:]

} catch {
print("error")
}
return [:]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// File.swift
//
//
// Created by oem on 10/10/24.
//

import Foundation

class ProcessJWKFromKID {
static func parseDIDJWK(_ didJwk: String) -> [String: Any]? {
guard didJwk.hasPrefix("did:jwk:") else {
return nil
}

let base64UrlValue = didJwk.replacingOccurrences(of: "did:jwk:", with: "")

guard let jsonString = base64UrlValue.decodeBase64(),
let jsonData = jsonString.data(using: .utf8),
let jwk = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] else {
return nil
}

return jwk
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// File.swift
//
//
// Created by oem on 10/10/24.
//

import Foundation

class ProcessKeyJWKFromKID {
static func processJWKfromKid(did: String?) -> [String: Any] {
guard let did = did else { return [:]}
let components = did.split(separator: "#")
guard let didPart = components.first else {
return [:]
}
return DidService.shared.createJWKfromDID(did: String(didPart))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// File.swift
//
//
// Created by oem on 10/10/24.
//

import Foundation

class ProcessWebJWKFromKID {
static func fetchDIDDocument(did: String) async throws -> [String: Any]? {
guard did.hasPrefix("did:web:") else { return nil }

let didWithoutPrefix = did.replacingOccurrences(of: "did:web:", with: "")
let didParts = didWithoutPrefix.split(separator: ":")

guard didParts.count > 1 else { return nil }

let host = didParts[0]
let path = didParts[1].split(separator: "#").first ?? ""
let didDocURLString = "https://\(host)/\(path)/did.json"

guard let didDocURL = URL(string: didDocURLString) else { return nil }

let (data, response) = try await URLSession.shared.data(from: didDocURL)

guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
return nil
}

let didDoc = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]

return didDoc
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,107 +14,40 @@ class SignatureValidator {

static func validateSign(jwt: String?, jwksURI: String?, format: String) async -> Bool? {
var jwk: [String: Any] = [:]
if format == "mso_mdoc" {
return true
if format == "mso_mdoc" {
return true
} else {
guard let split = jwt?.split(separator: "."), split.count > 1 else { return true}
guard let jsonString = "\(split[0])".decodeBase64(),
let jsonObject = UIApplicationUtils.shared.convertStringToDictionary(text: jsonString) else { return false }
if let kid = jsonObject["kid"] as? String {
if kid.hasPrefix("did:key:z") {
jwk = processJWKfromKid(did: kid)
} else if kid.hasPrefix("did:ebsi:z") {
jwk = await processJWKforEBSI(did: kid)
let jsonObject = UIApplicationUtils.shared.convertStringToDictionary(text: jsonString) else { return false }
if var kid = jsonObject["kid"] as? String {
if kid.hasPrefix("did:jwk:") {
if let parsedJWK = ProcessJWKFromKID.parseDIDJWK(kid) {
jwk = parsedJWK
}
} else if kid.hasPrefix("did:key:z") {
jwk = ProcessKeyJWKFromKID.processJWKfromKid(did: kid)
} else if kid.hasPrefix("did:ebsi:z") {
jwk = await ProcessEbsiJWKFromKID.processJWKforEBSI(did: kid)
} else if kid.hasPrefix("did:web:") {
if let didDocument = try? await ProcessWebJWKFromKID.fetchDIDDocument(did: kid),
let verificationMethod = didDocument["verificationMethod"] as? [[String: Any]],
let publicKeyJwk = verificationMethod.first?["publicKeyJwk"] as? [String: Any] {
jwk = publicKeyJwk
} else {
print("Failed to fetch or parse DID document for did:web")
return false
}

} else {
jwk = await ProcessJWKFromJwksUri.processJWKFromJwksURI2(kid: kid, jwksURI: jwksURI)
}
} else {
jwk = await processJWKFromJwksURI2(kid: kid, jwksURI: jwksURI)
let kid = jsonObject["kid"] as? String
jwk = await ProcessJWKFromJwksUri.processJWKFromJwksURI2(kid: kid, jwksURI: jwksURI)
}
} else {
let kid = jsonObject["kid"] as? String
jwk = await processJWKFromJwksURI2(kid: kid, jwksURI: jwksURI)
return validateSignature(jwt: jwt, jwk: jwk)
}
return validateSignature(jwt: jwt, jwk: jwk)
}
}


static func processJWKfromKid(did: String?) -> [String: Any] {
guard let did = did else { return [:]}
let components = did.split(separator: "#")
guard let didPart = components.first else {
return [:]
}
return DidService.shared.createJWKfromDID(did: String(didPart))
}

static func processJWKforEBSI(did: String?) async -> [String: Any]{
guard let did = did else { return [:]}
let ebsiEndPoint = "https://api-conformance.ebsi.eu/did-registry/v5/identifiers/\(did)"
let pilotEndpoint = "https://api-pilot.ebsi.eu/did-registry/v5/identifiers/\(did)"

do {
guard let url = URL(string: ebsiEndPoint) else { return [:] }
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse else { return [:] }

if httpResponse.statusCode == 200 {
// Process the response from the first URL
return try processPublicKeyFromJWKList(data)
} else {
// Call the fallback URL if the status is not 200
return try await fetchJWKListFromUrl(pilotEndpoint)
}
} catch {
print("Error fetching from primary URL: \(error)")
}
return [:]
}

private static func processPublicKeyFromJWKList(_ data: Data) throws -> [String: Any] {
guard let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let verificationMethods = jsonObject["verificationMethod"] as? [[String: Any]] else { return [:] }

for method in verificationMethods {
if let publicKeyJwk = method["publicKeyJwk"] as? [String: Any],
let crv = publicKeyJwk["crv"] as? String, crv == "P-256" {
return publicKeyJwk
}
}
return [:]
}

private static func fetchJWKListFromUrl(_ fallbackURL: String) async throws -> [String: Any] {
guard let url = URL(string: fallbackURL) else { return [:] }
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return [:] }

return try processPublicKeyFromJWKList(data)
}

static func processJWKFromJwksURI2(kid: String?, jwksURI: String?) async -> [String: Any] {
guard let jwksURI = jwksURI else {return [:]}
return await fetchJwkData(kid: kid, jwksUri: jwksURI)
}

static func fetchJwkData(kid: String?, jwksUri: String)async -> [String: Any] {
guard let url = URL(string: jwksUri) else {
return [:]
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return [:]}
guard let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let keys = jsonObject["keys"] as? [[String: Any]] else { return [:]}

var jwkKey: [String: Any]? = keys.first { $0["use"] as? String == "sig" }

if jwkKey == nil, let kid = kid {
jwkKey = keys.first { $0["kid"] as? String == kid }
}
return jwkKey ?? [:]

} catch {
print("error")
}
return [:]
}

static private func validateSignature(jwt: String?, jwk: [String: Any]) -> Bool? {
Expand Down Expand Up @@ -219,5 +152,4 @@ class SignatureValidator {
return false
}
}

}

0 comments on commit dd91288

Please sign in to comment.