This commit is contained in:
sydneymorton 2020-10-08 17:04:35 -07:00
Родитель 2d57a27529
Коммит 8073174d98
17 изменённых файлов: 55 добавлений и 50 удалений

Просмотреть файл

@ -24,6 +24,7 @@
551F3068252E97000081D5E7 /* IdentifierCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551F3067252E97000081D5E7 /* IdentifierCreator.swift */; };
55253976252FCA6D003202D5 /* VCCrypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55253975252FCA6D003202D5 /* VCCrypto.framework */; };
55253977252FCA6D003202D5 /* VCCrypto.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 55253975252FCA6D003202D5 /* VCCrypto.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
55253982252FDF89003202D5 /* KeyContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55253981252FDF89003202D5 /* KeyContainer.swift */; };
55575738251BC575009979AB /* VCEntities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5557572E251BC575009979AB /* VCEntities.framework */; };
5557573D251BC575009979AB /* VCEntitiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5557573C251BC575009979AB /* VCEntitiesTests.swift */; };
5557573F251BC575009979AB /* VCEntities.h in Headers */ = {isa = PBXBuildFile; fileRef = 55575731251BC575009979AB /* VCEntities.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -123,6 +124,7 @@
551F3065252E71680081D5E7 /* MultihashTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultihashTests.swift; sourceTree = "<group>"; };
551F3067252E97000081D5E7 /* IdentifierCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentifierCreator.swift; sourceTree = "<group>"; };
55253975252FCA6D003202D5 /* VCCrypto.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VCCrypto.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55253981252FDF89003202D5 /* KeyContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyContainer.swift; sourceTree = "<group>"; };
5557572E251BC575009979AB /* VCEntities.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = VCEntities.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55575731251BC575009979AB /* VCEntities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VCEntities.h; sourceTree = "<group>"; };
55575732251BC575009979AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -353,6 +355,7 @@
55AF7482252F6A7E006A8B25 /* document */,
55AF748D252F6BE0006A8B25 /* Identifier.swift */,
551F3067252E97000081D5E7 /* IdentifierCreator.swift */,
55253981252FDF89003202D5 /* KeyContainer.swift */,
);
path = identifier;
sourceTree = "<group>";
@ -584,6 +587,7 @@
5518CC7625264D5700C7A21B /* ResponseMappings.swift in Sources */,
551F3068252E97000081D5E7 /* IdentifierCreator.swift in Sources */,
551F305B252E39540081D5E7 /* IdentifierFormatter.swift in Sources */,
55253982252FDF89003202D5 /* KeyContainer.swift in Sources */,
557BFC53251E665D005B5B24 /* IssuanceResponseFormatter.swift in Sources */,
5584E4A02525656500A9DE58 /* SchemaDescriptor.swift in Sources */,
55575766251BC6CF009979AB /* LogoDisplayDescriptor.swift in Sources */,

Просмотреть файл

@ -14,6 +14,6 @@ func createTokenTimeConstraints(expiryInSeconds: Int) -> TokenTimeConstraints {
}
func formatHeaders(usingIdentifier identifier: Identifier, andSigningKey key: KeyContainer) -> Header {
let keyId = identifier.longformId + "#" + key.keyId
let keyId = identifier.longFormDid + "#" + key.keyId
return Header(type: jwtType, algorithm: key.algorithm, keyId: keyId)
}

Просмотреть файл

@ -6,7 +6,7 @@
import VCJwt
protocol IdentifierFormatting {
func createIonLongForm(recoveryKey: ECPublicJwk,
func createIonLongFormDid(recoveryKey: ECPublicJwk,
updateKey: ECPublicJwk,
didDocumentKeys: [ECPublicJwk],
serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String
@ -17,18 +17,18 @@ struct IdentifierFormatter: IdentifierFormatting {
private let multihash: Multihash = Multihash()
private let encoder: JSONEncoder = JSONEncoder()
private let ionPrefix = "did:ion:"
private let ionQueryValue = "?-ion-initial-state="
private let replaceAction = "replace"
private static let ionPrefix = "did:ion:"
private static let ionQueryValue = "?-ion-initial-state="
private static let replaceAction = "replace"
func createIonLongForm(recoveryKey: ECPublicJwk,
func createIonLongFormDid(recoveryKey: ECPublicJwk,
updateKey: ECPublicJwk,
didDocumentKeys: [ECPublicJwk],
serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String {
let document = IdentifierDocument(fromJwks: didDocumentKeys, andServiceEndpoints: serviceEndpoints)
let patches = [IdentifierDocumentPatch(action: replaceAction, document: document)]
let patches = [IdentifierDocumentPatch(action: IdentifierFormatter.replaceAction, document: document)]
let commitmentHash = try self.createCommitmentHash(usingJwk: updateKey)
let delta = IdentifierDocumentDeltaDescriptor(updateCommitment: commitmentHash, patches: patches)
@ -46,7 +46,7 @@ struct IdentifierFormatter: IdentifierFormatting {
let shortForm = try self.createShortFormIdentifier(usingSuffixData: suffixData)
return shortForm + ionQueryValue + encodedPayload
return shortForm + IdentifierFormatter.ionQueryValue + encodedPayload
}
private func createShortFormIdentifier(usingSuffixData data: SuffixDescriptor) throws -> String {
@ -54,7 +54,7 @@ struct IdentifierFormatter: IdentifierFormatting {
let encodedData = try encoder.encode(data)
let hashedSuffixData = multihash.compute(from: encodedData).base64URLEncodedString()
return ionPrefix + hashedSuffixData
return IdentifierFormatter.ionPrefix + hashedSuffixData
}
private func createSuffixData(usingDelta delta: IdentifierDocumentDeltaDescriptor, recoveryKey: ECPublicJwk) throws -> SuffixDescriptor {

Просмотреть файл

@ -37,7 +37,7 @@ public class IssuanceResponseFormatter: IssuanceResponseFormatting {
return IssuanceResponseClaims(publicKeyThumbprint: try publicKey.getThumbprint(),
audience: response.audience,
did: identifier.longformId,
did: identifier.longFormDid,
publicJwk: publicKey,
contract: response.contractUri,
jti: UUID().uuidString,

Просмотреть файл

@ -49,7 +49,7 @@ public class PresentationResponseFormatter: PresentationResponseFormatting {
return PresentationResponseClaims(publicKeyThumbprint: try publicKey.getThumbprint(),
audience: response.request.content.redirectURI,
did: identifier.longformId,
did: identifier.longFormDid,
publicJwk: publicKey,
jti: UUID().uuidString,
presentationSubmission: presentationSubmission,

Просмотреть файл

@ -30,7 +30,7 @@ class VerifiablePresentationFormatter {
let vpClaims = VerifiablePresentationClaims(vpId: UUID().uuidString,
purpose: PURPOSE,
verifiablePresentation: verifiablePresentationDescriptor,
issuerOfVp: identifier.longformId,
issuerOfVp: identifier.longFormDid,
audience: audience,
iat: timeConstraints.issuedAt,
exp: timeConstraints.expiration)

Просмотреть файл

@ -6,36 +6,18 @@
import VCCrypto
public struct Identifier {
public let longformId: String
public let longFormDid: String
let didDocumentKeys: [KeyContainer]
let updateKey: KeyContainer
let recoveryKey: KeyContainer
public init(longformId: String,
public init(longFormDid: String,
didDocumentKeys: [KeyContainer],
updateKey: KeyContainer,
recoveryKey: KeyContainer) {
self.longformId = longformId
self.longFormDid = longFormDid
self.didDocumentKeys = didDocumentKeys
self.updateKey = updateKey
self.recoveryKey = recoveryKey
}
}
public struct KeyContainer {
/// key reference to key in Secret Store
let keyReference: VCCryptoSecret
/// keyId to specify key in Identifier Document (must be less than 20 chars long)
let keyId: String
/// Always ES256K because we only support Secp256k1 keys
let algorithm: String = "ES256K"
public init(keyReference: VCCryptoSecret,
keyId: String) {
self.keyReference = keyReference
self.keyId = keyId
}
}

Просмотреть файл

@ -27,7 +27,7 @@ public struct IdentifierCreator {
let recoveryKeyContainer = KeyContainer(keyReference: try self.cryptoOperations.generateKey(), keyId: "recover")
let longformDid = try self.createLongformDid(signingKeyContainer: signingKeyContainer, updateKeyContainer: updateKeyContainer, recoveryKeyContainer: recoveryKeyContainer)
return Identifier(longformId: longformDid, didDocumentKeys: [signingKeyContainer], updateKey: updateKeyContainer, recoveryKey: recoveryKeyContainer)
return Identifier(longFormDid: longformDid, didDocumentKeys: [signingKeyContainer], updateKey: updateKeyContainer, recoveryKey: recoveryKeyContainer)
}
@ -35,7 +35,7 @@ public struct IdentifierCreator {
let signingJwk = try self.generatePublicJwk(for: signingKeyContainer)
let updateJwk = try self.generatePublicJwk(for: updateKeyContainer)
let recoveryJwk = try self.generatePublicJwk(for: recoveryKeyContainer)
return try self.identifierFormatter.createIonLongForm(recoveryKey: recoveryJwk, updateKey: updateJwk, didDocumentKeys: [signingJwk], serviceEndpoints: [])
return try self.identifierFormatter.createIonLongFormDid(recoveryKey: recoveryJwk, updateKey: updateJwk, didDocumentKeys: [signingJwk], serviceEndpoints: [])
}
private func generatePublicJwk(for keyMapping: KeyContainer) throws -> ECPublicJwk {

Просмотреть файл

@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import VCCrypto
public struct KeyContainer {
/// key reference to key in Secret Store
let keyReference: VCCryptoSecret
/// keyId to specify key in Identifier Document (must be less than 20 chars long)
let keyId: String
/// Always ES256K because we only support Secp256k1 keys
let algorithm: String = "ES256K"
public init(keyReference: VCCryptoSecret,
keyId: String) {
self.keyReference = keyReference
self.keyId = keyId
}
}

Просмотреть файл

@ -42,8 +42,6 @@ public extension KeyedDecodingContainer {
}
}
public extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
mutating func encode(_ value: Dictionary<String, Any>) throws {
try value.forEach({ (key, value) in
@ -76,4 +74,3 @@ public extension KeyedEncodingContainerProtocol {
}
}
}

Просмотреть файл

@ -15,10 +15,8 @@ class IdentifierFormatterTests: XCTestCase {
func testFormatting() throws {
let key = ECPublicJwk(x: "Ir5lqT2yDCXdWI8HgMj2erz9HVChFFv4Bd70oDqclvs", y: "_uSQb2NNO3MMnsS83ByMxayGbk3ODYxAlMx-_YOw5oc", keyId: "testKey")
let actualDid = try formatter.createIonLongForm(recoveryKey: key, updateKey: key, didDocumentKeys: [key], serviceEndpoints: [])
let actualDid = try formatter.createIonLongFormDid(recoveryKey: key, updateKey: key, didDocumentKeys: [key], serviceEndpoints: [])
XCTAssertEqual(actualDid, expectedDid)
}
}

Просмотреть файл

@ -29,12 +29,12 @@ class IssuanceResponseFormatterTests: XCTestCase {
let key = try cryptoOperation.generateKey()
let keyContainer = KeyContainer(keyReference: key, keyId: "keyId")
self.mockIdentifier = Identifier(longformId: "longFormDid", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
self.mockIdentifier = Identifier(longFormDid: "longFormDid", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
}
func testFormatToken() throws {
let formattedToken = try formatter.format(response: self.mockResponse, usingIdentifier: self.mockIdentifier)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longformId)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longFormDid)
XCTAssertEqual(formattedToken.content.contract, self.mockResponse.contractUri)
XCTAssertEqual(formattedToken.content.audience, self.mockResponse.audience)
XCTAssert(MockTokenSigner.wasSignCalled)

Просмотреть файл

@ -31,7 +31,7 @@ class PresentationResponseFormatterTests: XCTestCase {
let key = try cryptoOperation.generateKey()
let keyContainer = KeyContainer(keyReference: key, keyId: "keyId")
self.mockIdentifier = Identifier(longformId: "longFormDid", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
self.mockIdentifier = Identifier(longFormDid: "longFormDid", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
}
func testFormatToken() throws {
@ -40,7 +40,7 @@ class PresentationResponseFormatterTests: XCTestCase {
let formattedToken = try formatter.format(response: self.mockResponse, usingIdentifier: self.mockIdentifier)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longformId)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longFormDid)
XCTAssertNotNil(formattedToken.content.exp)
XCTAssertNotNil(formattedToken.content.iat)
XCTAssertNotNil(formattedToken.content.jti)
@ -59,7 +59,7 @@ class PresentationResponseFormatterTests: XCTestCase {
func testFormatTokenNoVcs() throws {
let formattedToken = try formatter.format(response: self.mockResponse, usingIdentifier: self.mockIdentifier)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longformId)
XCTAssertEqual(formattedToken.content.did, self.mockIdentifier.longFormDid)
XCTAssertNotNil(formattedToken.content.exp)
XCTAssertNotNil(formattedToken.content.iat)
XCTAssertNotNil(formattedToken.content.jti)

Просмотреть файл

@ -24,7 +24,7 @@ class IdentifierCreatorTests: XCTestCase {
let creator = IdentifierCreator(cryptoOperations: self.cryptoOperations, identifierFormatter: MockIdentifierFormatter(returningString: self.expectedResult))
let actualResult = try creator.create()
XCTAssertEqual(MockCryptoOperations.generateKeyCallCount, 3)
XCTAssertEqual(actualResult.longformId, expectedResult)
XCTAssertEqual(actualResult.longFormDid, expectedResult)
}
func testCreateIdentifierWithCryptoOperations() throws {

Просмотреть файл

@ -15,7 +15,7 @@ struct MockIdentifierFormatter: IdentifierFormatting {
self.returningString = returningString
}
func createIonLongForm(recoveryKey: ECPublicJwk, updateKey: ECPublicJwk, didDocumentKeys: [ECPublicJwk], serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String {
func createIonLongFormDid(recoveryKey: ECPublicJwk, updateKey: ECPublicJwk, didDocumentKeys: [ECPublicJwk], serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String {
return self.returningString
}
}

Просмотреть файл

@ -25,7 +25,7 @@ class IssuanceUseCaseTests: XCTestCase {
self.contract = try JSONDecoder().decode(Contract.self, from: encodedContract)
let keyContainer = KeyContainer(keyReference: MockVCCryptoSecret(), keyId: "keyId234")
self.mockIdentifier = Identifier(longformId: "longform", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
self.mockIdentifier = Identifier(longFormDid: "longform", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
MockIssuanceResponseFormatter.wasFormatCalled = false
MockApiCalls.wasPostCalled = false

Просмотреть файл

@ -24,7 +24,7 @@ class PresentationUseCaseTests: XCTestCase {
self.presentationRequest = PresentationRequest(from: TestData.presentationRequest.rawValue)!
let keyContainer = KeyContainer(keyReference: MockVCCryptoSecret(), keyId: "keyId234")
self.mockIdentifier = Identifier(longformId: "longform", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
self.mockIdentifier = Identifier(longFormDid: "longform", didDocumentKeys: [keyContainer], updateKey: keyContainer, recoveryKey: keyContainer)
MockPresentationResponseFormatter.wasFormatCalled = false
MockApiCalls.wasPostCalled = false