Add exchange model and formatter

This commit is contained in:
sydneymorton 2020-11-09 17:15:13 -08:00
Родитель 9b72f009ab
Коммит a325ab6384
6 изменённых файлов: 165 добавлений и 2 удалений

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

@ -60,6 +60,9 @@
5577E86F251E8EB3005250BC /* IssuanceServiceResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5577E86E251E8EB3005250BC /* IssuanceServiceResponseTests.swift */; };
5577E871251E8FE3005250BC /* OIDCClaimsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5577E870251E8FE3005250BC /* OIDCClaimsTests.swift */; };
5577E873251E9007005250BC /* MockOIDCClaims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5577E872251E9007005250BC /* MockOIDCClaims.swift */; };
55793BCB255A0497007F7599 /* ExchangeResponseClaims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55793BCA255A0497007F7599 /* ExchangeResponseClaims.swift */; };
55793BCD255A070E007F7599 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55793BCC255A070E007F7599 /* Constants.swift */; };
55793BCF255A08FE007F7599 /* ExchangeResponseFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55793BCE255A08FE007F7599 /* ExchangeResponseFormatter.swift */; };
557BFC46251E6058005B5B24 /* IssuanceResponseClaimsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557BFC45251E6058005B5B24 /* IssuanceResponseClaimsTests.swift */; };
557BFC53251E665D005B5B24 /* IssuanceResponseFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557BFC51251E665D005B5B24 /* IssuanceResponseFormatter.swift */; };
557BFC56251E6701005B5B24 /* IssuanceResponseContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557BFC55251E6701005B5B24 /* IssuanceResponseContainer.swift */; };
@ -150,6 +153,9 @@
5577E86E251E8EB3005250BC /* IssuanceServiceResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssuanceServiceResponseTests.swift; sourceTree = "<group>"; };
5577E870251E8FE3005250BC /* OIDCClaimsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCClaimsTests.swift; sourceTree = "<group>"; };
5577E872251E9007005250BC /* MockOIDCClaims.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockOIDCClaims.swift; sourceTree = "<group>"; };
55793BCA255A0497007F7599 /* ExchangeResponseClaims.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeResponseClaims.swift; sourceTree = "<group>"; };
55793BCC255A070E007F7599 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
55793BCE255A08FE007F7599 /* ExchangeResponseFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangeResponseFormatter.swift; sourceTree = "<group>"; };
557BFC45251E6058005B5B24 /* IssuanceResponseClaimsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssuanceResponseClaimsTests.swift; sourceTree = "<group>"; };
557BFC51251E665D005B5B24 /* IssuanceResponseFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssuanceResponseFormatter.swift; sourceTree = "<group>"; };
557BFC55251E6701005B5B24 /* IssuanceResponseContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssuanceResponseContainer.swift; sourceTree = "<group>"; };
@ -248,6 +254,7 @@
children = (
557BFC50251E665D005B5B24 /* formatters */,
5577E865251E830B005250BC /* identifier */,
55793BC8255A0468007F7599 /* exchange */,
5577E862251E8284005250BC /* issuance */,
5584E49725255A8F00A9DE58 /* presentation */,
5577E864251E82B2005250BC /* verifiableCredential */,
@ -364,11 +371,28 @@
path = issuance;
sourceTree = "<group>";
};
55793BC8255A0468007F7599 /* exchange */ = {
isa = PBXGroup;
children = (
55793BC9255A0484007F7599 /* claims */,
);
path = exchange;
sourceTree = "<group>";
};
55793BC9255A0484007F7599 /* claims */ = {
isa = PBXGroup;
children = (
55793BCA255A0497007F7599 /* ExchangeResponseClaims.swift */,
);
path = claims;
sourceTree = "<group>";
};
557BFC50251E665D005B5B24 /* formatters */ = {
isa = PBXGroup;
children = (
557BFC51251E665D005B5B24 /* IssuanceResponseFormatter.swift */,
551F305A252E39540081D5E7 /* IdentifierFormatter.swift */,
55793BCE255A08FE007F7599 /* ExchangeResponseFormatter.swift */,
5518CC7125264C6F00C7A21B /* PresentationResponseFormatter.swift */,
555CE08925267FE500C1C938 /* VerifiablePresentationFormatter.swift */,
551F30422527DC050081D5E7 /* JwsHeaderFormatter .swift */,
@ -433,6 +457,7 @@
55AF7481252F6803006A8B25 /* util */ = {
isa = PBXGroup;
children = (
55793BCC255A070E007F7599 /* Constants.swift */,
55575762251BC6CF009979AB /* JSONCodingKeys.swift */,
551F3062252E6E230081D5E7 /* Multihash.swift */,
);
@ -603,6 +628,7 @@
55575773251BC6CF009979AB /* VerifiableCredentialDescriptor.swift in Sources */,
555CE08F2526822300C1C938 /* VerifiablePresentationDescriptor.swift in Sources */,
55575770251BC6CF009979AB /* OIDCClaims.swift in Sources */,
55793BCF255A08FE007F7599 /* ExchangeResponseFormatter.swift in Sources */,
5557576C251BC6CF009979AB /* CardDisplayDescriptor.swift in Sources */,
55AF748E252F6BE0006A8B25 /* Identifier.swift in Sources */,
55AF7486252F6B1F006A8B25 /* IdentifierDocumentServiceEndpoint.swift in Sources */,
@ -611,10 +637,12 @@
551F305D252E4C1B0081D5E7 /* IdentifierDocument.swift in Sources */,
55575777251BC6CF009979AB /* IssuanceServiceResponse.swift in Sources */,
55309B762539DDC300AF15AA /* VerifiableCredential.swift in Sources */,
55793BCB255A0497007F7599 /* ExchangeResponseClaims.swift in Sources */,
551F30432527DC050081D5E7 /* JwsHeaderFormatter .swift in Sources */,
55575765251BC6CF009979AB /* ConsentDisplayDescriptor.swift in Sources */,
5584E49C2525641600A9DE58 /* PresentationDefinition.swift in Sources */,
555CE08D2526810100C1C938 /* VerifiablePresentationClaims.swift in Sources */,
55793BCD255A070E007F7599 /* Constants.swift in Sources */,
5584E4A2252565D900A9DE58 /* IssuanceMetadata.swift in Sources */,
5518CC68252645D000C7A21B /* PresentationSubmission.swift in Sources */,
5557576A251BC6CF009979AB /* Contract.swift in Sources */,

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

@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import VCJwt
public struct ExchangeResponseClaims: OIDCClaims {
public let issuer: String = Constants.SELF_ISSUED
public let publicKeyThumbprint: String
public let audience: String
public let did: String
public let publicJwk: ECPublicJwk?
public let contract: String
public let jti: String
public let iat: Double?
public let exp: Double?
public let exchangeableVc: String
public let recipientDid: String
public init(publicKeyThumbprint: String = "",
audience: String = "",
did: String = "",
publicJwk: ECPublicJwk? = nil,
contract: String = "",
jti: String = "",
iat: Double? = nil,
exp: Double? = nil,
exchangeableVc: String = "",
recipientDid: String = "") {
self.publicKeyThumbprint = publicKeyThumbprint
self.audience = audience
self.did = did
self.publicJwk = publicJwk
self.contract = contract
self.jti = jti
self.iat = iat
self.exp = exp
self.exchangeableVc = exchangeableVc
self.recipientDid = recipientDid
}
enum CodingKeys: String, CodingKey {
case issuer = "iss"
case publicKeyThumbprint = "sub"
case audience = "aud"
case publicJwk = "sub_jwk"
case exchangeableVc = "vc"
case recipientDid = "recipient"
case contract, jti, did, iat, exp
}
}
public typealias ExchangeResponse = JwsToken<ExchangeResponseClaims>

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

@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import VCJwt
public protocol ExchangeResponseFormatting {
func format(usingIdentifier identifier: Identifier, andExchangeableVc vc: VerifiableCredential) throws -> ExchangeResponse
}
public class ExchangeResponseFormatter: ExchangeResponseFormatting {
let signer: TokenSigning
let headerFormatter = JwsHeaderFormatter()
public init(signer: TokenSigning = Secp256k1Signer()) {
self.signer = signer
}
public func format(usingIdentifier identifier: Identifier, andExchangeableVc vc: VerifiableCredential) throws -> ExchangeResponse {
guard let signingKey = identifier.didDocumentKeys.first else {
throw FormatterError.noSigningKeyFound
}
return try createToken(usingIdentifier: identifier, andExchangeableVc: vc, andSignWith: signingKey)
}
private func createToken(usingIdentifier identifier: Identifier, andExchangeableVc vc: VerifiableCredential, andSignWith signingKey: KeyContainer) throws -> ExchangeResponse {
let headers = headerFormatter.formatHeaders(usingIdentifier: identifier, andSigningKey: signingKey)
let tokenContents = try formatClaims(usingIdentifier: identifier, andExchangeableVc: vc, andSigningKey: signingKey)
guard var token = JwsToken(headers: headers, content: tokenContents) else {
throw FormatterError.unableToFormToken
}
try token.sign(using: self.signer, withSecret: signingKey.keyReference)
return token
}
private func formatClaims(usingIdentifier identifier: Identifier, andExchangeableVc vc: VerifiableCredential, andSigningKey key: KeyContainer) throws -> ExchangeResponseClaims {
guard let audience = vc.token.content.vc.exchangeService?.id else {
throw FormatterError.noAudienceFoundInRequest
}
let publicKey = try signer.getPublicJwk(from: key.keyReference, withKeyId: key.keyId)
let timeConstraints = TokenTimeConstraints(expiryInSeconds: 5)
return ExchangeResponseClaims(publicKeyThumbprint: try publicKey.getThumbprint(),
audience: audience,
did: vc.token.content.sub,
publicJwk: publicKey,
jti: UUID().uuidString,
iat: timeConstraints.issuedAt,
exp: timeConstraints.expiration,
exchangeableVc: vc.raw,
recipientDid: identifier.longFormDid)
}
}

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

@ -7,7 +7,7 @@ import VCJwt
public struct IssuanceResponseClaims: OIDCClaims {
public let issuer: String = "https://self-issued.me"
public let issuer: String = Constants.SELF_ISSUED
public let publicKeyThumbprint: String

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

@ -7,7 +7,7 @@ import VCJwt
public struct PresentationResponseClaims: OIDCClaims {
public let issuer: String = "https://self-issued.me"
public let issuer: String = Constants.SELF_ISSUED
public let publicKeyThumbprint: String

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

@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
struct Constants {
static let SELF_ISSUED = "https://self-issued.me"
}