Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issuance unit tests #9

Merged
merged 6 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 33 additions & 53 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,42 @@
# EU Digital Identity Wallet Vulnerability Disclosure Policy (VDP)

At the European Commission, we treat the security of our Communication and Information Systems as a
top priority, in line with Commission Decision EC 2017/46. However, vulnerabilities can never be
completely eliminated, despite all efforts. If exploited, such vulnerabilities can harm the
confidentiality, integrity or availability of the Commission's systems and of the information
processed therein. To identify and remediate vulnerabilities as soon as possible, we value the input
of external entities acting in good faith, and we encourage responsible vulnerability research and
disclosure. This document sets out our definition of good faith in the context of finding and
reporting vulnerabilities, as well as what you can expect from us in return.
At the European Commission, we treat the security of our Communication and Information Systems as a top priority, in line with Commission Decision EC 2017/46. However, vulnerabilities can never be completely eliminated, despite all efforts. If exploited, such vulnerabilities can harm the confidentiality, integrity or availability of the Commission's systems and of the information processed therein. To identify and remediate vulnerabilities as soon as possible, we value the input of external entities acting in good faith, and we encourage responsible vulnerability research and disclosure. This document sets out our definition of good faith in the context of finding and reporting vulnerabilities, as well as what you can expect from us in return.

## Scope

- Architecture and Reference Framework
- Source code in [eu-digital-identity-wallet](https://github.com/eu-digital-identity-wallet) public
repositories

## If you have identified a vulnerability, please do the following:

* E-mail your findings to [email protected], specifying whether or not you
agree to your name or pseudonym being made publicly available as the discoverer of the problem.
* Encrypt your findings using
our [PGP key](https://sks.hnet.se/pks/lookup?search=EC-VULNERABILITY-DISCLOSURE%40ec.europa.eu&fingerprint=on&op=index)
to prevent this critical information from falling into the wrong hands.
* Provide us sufficient information to reproduce the problem so that we can resolve it as quickly as
possible. Usually, the IP address or the URL of the affected system and a description of the
vulnerability will be sufficient, but complex vulnerabilities may require further explanation in
terms of technical information or potential proof-of-concept code.
* Provide your report in English, preferably, or in any other official language of the European
Union.
* Inform us if you agree to make your name/pseudonym publicly available as the discoverer of the
vulnerability.
- Source code in [eu-digital-identity-wallet](https://github.com/eu-digital-identity-wallet) public repositories

## If you have identified a vulnerability, please do the following

- E-mail your findings to <[email protected]>, specifying whether or not you agree to your name or pseudonym being made publicly available as the discoverer of the problem.
- Encrypt your findings using our [PGP key](https://pgp.mit.edu/pks/lookup?op=get&search=0x6773AACDF09F6628) to prevent this critical information from falling into the wrong hands.
- Provide us with sufficient information to reproduce the problem so that we can resolve it as quickly as possible. Usually, the IP address or the URL of the affected system and a description of the vulnerability will be sufficient, but complex vulnerabilities may require further explanation in terms of technical information or potential proof-of-concept code.
- Provide your report in English, preferably, or in any other official language of the European Union.
- Inform us if you agree to make your name/pseudonym publicly available as the discoverer of the vulnerability.

## Please do not do the following

* Do not take advantage of the vulnerability or problem you have discovered, for example by
downloading more data than necessary to demonstrate the vulnerability, deleting, or modifying
other people’s data.
* Do not reveal any data downloaded during the discovery to any other parties.
* Do not reveal the problem to others until it has been resolved.
* Do not perform the following actions:
* Placing malware (virus, worm, Trojan horse, etc.) within the system.
* Reading, copying, modifying or deleting data from the system.
* Making changes to the system.
* Repeatedly accessing the system or sharing access with others.
* Using any access obtained to attempt to access other systems.
* Changing access rights for any other users.
* Using automated scanning tools.
* Using the so-called "brute force" of access to the system.
* Using denial-of-service or social engineering (phishing, vishing, spam etc.).
* Do not use attacks on physical security.

## What we promise:

* We will respond to your report within three business days with our evaluation of the report.
* We will handle your report with strict confidentiality.
* Where possible, we will inform you when the vulnerability has been remedied.
* We will process the personal data that you provide (such as your e-mail address and name) in
accordance with the applicable data protection legislation and will not pass on your personal
details to third parties without your permission.
* In the public information concerning the problem reported, we will publish your name as the
discoverer of the problem if you have agreed to this in your initial e-mail
- Do not take advantage of the vulnerability or problem you have discovered, for example, by downloading more data than necessary to demonstrate the vulnerability, deleting, or modifying other people’s data.
- Do not reveal any data downloaded during the discovery to any other parties.
- Do not reveal the problem to others until it has been resolved.
- Do not perform the following actions:
- Placing malware (virus, worm, Trojan horse, etc.) within the system.
- Reading, copying, modifying or deleting data from the system.
- Making changes to the system.
- Repeatedly accessing the system or sharing access with others.
- Using any access obtained to attempt to access other systems.
- Changing access rights for any other users.
- Using automated scanning tools.
- Using the so-called "brute force" of access to the system.
- Using denial-of-service or social engineering (phishing, vishing, spam, etc.).
- Do not use attacks on physical security.

## What we promise

- We will respond to your report within three business days with our evaluation of the report.

- We will handle your report with strict confidentiality.
- Where possible, we will inform you when the vulnerability has been remedied.
- We will process the personal data that you provide (such as your e-mail address and name) in accordance with the applicable data protection legislation and will not pass on your personal details to third parties without your permission.
- In the public information concerning the problem reported, we will publish your name as the discoverer of the problem if you have agreed to this in your initial e-mail
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public extension SupportedCredential {
proof: proof
)
default:
throw ValidationError.error(reason: "Unsupported profile for issueance request")
throw ValidationError.error(reason: "Unsupported profile for issuance request")
}
}
}
63 changes: 63 additions & 0 deletions Sources/Entities/Errors/JOSEError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/
import Foundation
import JOSESwift

/*
This enum represents a set of JOSE (Javascript Object Signing and Encryption) errors.
Expand Down Expand Up @@ -52,3 +53,65 @@ public enum JOSEError: LocalizedError {
}
}
}

extension JOSESwiftError: LocalizedError {

public var errorDescription: String? {
switch self {
case .signingFailed(let description):
return ".signingFailed: \(description)"
case .verifyingFailed(let description):
return ".verifyingFailed: \(description)"
case .signatureInvalid:
return ".signatureInvalid"
case .encryptingFailed(let description):
return ".encryptingFailed: \(description)"
case .decryptingFailed:
return ".decryptingFailed"
case .wrongDataEncoding:
return ".wrongDataEncoding"
case .invalidCompactSerializationComponentCount(let count):
return ".invalidCompactSerializationComponentCount: \(count)"
case .componentNotValidBase64URL(let component):
return ".componentNotValidBase64URL: \(component)"
case .componentCouldNotBeInitializedFromData:
return ".componentCouldNotBeInitializedFromData"
case .couldNotConstructJWK:
return ".couldNotConstructJWK"
case .modulusNotBase64URLUIntEncoded:
return ".modulusNotBase64URLUIntEncoded"
case .exponentNotBase64URLUIntEncoded:
return ".exponentNotBase64URLUIntEncoded"
case .privateExponentNotBase64URLUIntEncoded:
return ""
case .symmetricKeyNotBase64URLEncoded:
return ".symmetricKeyNotBase64URLEncoded"
case .xNotBase64URLUIntEncoded:
return ".xNotBase64URLUIntEncoded"
case .yNotBase64URLUIntEncoded:
return ".yNotBase64URLUIntEncoded"
case .privateKeyNotBase64URLUIntEncoded:
return ".privateKeyNotBase64URLUIntEncoded"
case .invalidCurveType:
return ".invalidCurveType"
case .compressedCurvePointsUnsupported:
return ".compressedCurvePointsUnsupported"
case .invalidCurvePointOctetLength:
return ".invalidCurvePointOctetLength"
case .localAuthenticationFailed(let errorCode):
return ".localAuthenticationFailed: \(errorCode)"
case .compressionFailed:
return ".compressionFailed"
case .decompressionFailed:
return ".decompressionFailed"
case .compressionAlgorithmNotSupported:
return ".compressionAlgorithmNotSupported"
case .rawDataMustBeGreaterThanZero:
return ".rawDataMustBeGreaterThanZero"
case .compressedDataMustBeGreaterThanZero:
return ".compressedDataMustBeGreaterThanZero"
case .thumbprintSerialization:
return ".thumbprintSerialization"
}
}
}
7 changes: 4 additions & 3 deletions Sources/Issuers/IssuanceRequester.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public actor IssuanceRequester: IssuanceRequesterType {
public init(
issuerMetadata: CredentialIssuerMetadata,
service: AuthorisationServiceType = AuthorisationService(),
poster: PostingType = Poster()
poster: PostingType
) {
self.issuerMetadata = issuerMetadata
self.service = service
Expand Down Expand Up @@ -80,6 +80,7 @@ public actor IssuanceRequester: IssuanceRequesterType {
case .msoMdoc(let credential):
switch issuerMetadata.credentialResponseEncryption {
case .notRequired:
print(string)
guard let response = SingleIssuanceSuccessResponse.fromJSONString(string) else {
return .failure(ValidationError.todo(reason: "Cannot decode .notRequired response"))
}
Expand All @@ -104,7 +105,7 @@ public actor IssuanceRequester: IssuanceRequesterType {
let keyManagementAlgorithm = KeyManagementAlgorithm(algorithm: responseEncryptionAlg),
let contentEncryptionAlgorithm = ContentEncryptionAlgorithm(encryptionMethod: responseEncryptionMethod)
else {
return .failure(ValidationError.error(reason: "Unsupported encryption algorithms"))
return .failure(ValidationError.error(reason: "Unsupported encryption algorithms: \(responseEncryptionAlg.name), \(responseEncryptionMethod.name)"))
}

let jwe = try JWE(compactSerialization: string)
Expand All @@ -121,7 +122,7 @@ public actor IssuanceRequester: IssuanceRequesterType {
}

} catch {
return .failure(ValidationError.error(reason: error.localizedDescription))
return .failure(error)
}
}
case .sdJwtVc(let credential):
Expand Down
34 changes: 24 additions & 10 deletions Sources/Issuers/Issuer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,38 @@ public actor Issuer: IssuerType {
let config: WalletOpenId4VCIConfig

private let authorizer: IssuanceAuthorizerType
private let requester: IssuanceRequesterType

private let issuanceRequester: IssuanceRequesterType
private let deferredIssuanceRequester: IssuanceRequesterType

public init(
authorizationServerMetadata: IdentityAndAccessManagementMetadata,
issuerMetadata: CredentialIssuerMetadata,
config: WalletOpenId4VCIConfig
config: WalletOpenId4VCIConfig,
parPoster: PostingType = Poster(),
tokenPoster: PostingType = Poster(),
requesterPoster: PostingType = Poster(),
deferredRequesterPoster: PostingType = Poster()
) throws {
self.authorizationServerMetadata = authorizationServerMetadata
self.issuerMetadata = issuerMetadata
self.config = config

authorizer = try IssuanceAuthorizer(
parPoster: parPoster,
tokenPoster: tokenPoster,
config: config,
authorizationServerMetadata: authorizationServerMetadata
)

requester = IssuanceRequester(
issuerMetadata: issuerMetadata
issuanceRequester = IssuanceRequester(
issuerMetadata: issuerMetadata,
poster: requesterPoster
)

deferredIssuanceRequester = IssuanceRequester(
issuerMetadata: issuerMetadata,
poster: deferredRequesterPoster
)
}

Expand Down Expand Up @@ -287,7 +301,7 @@ public actor Issuer: IssuerType {
case .noProofRequired(let token):
return try await requestIssuance(token: token) {
return try supportedCredential.toIssuanceRequest(
requester: requester,
requester: issuanceRequester,
claimSet: claimSet,
responseEncryptionSpecProvider: responseEncryptionSpecProvider
)
Expand Down Expand Up @@ -316,10 +330,10 @@ public actor Issuer: IssuerType {
let cNonce = cNonce(from: proofRequest)
return try await requestIssuance(token: accessToken(from: proofRequest)) {
return try supportedCredential.toIssuanceRequest(
requester: requester,
requester: issuanceRequester,
claimSet: claimSet,
proof: bindingKey.toSupportedProof(
issuanceRequester: requester,
issuanceRequester: issuanceRequester,
credentialSpec: supportedCredential,
cNonce: cNonce?.value
),
Expand All @@ -338,7 +352,7 @@ private extension Issuer {
let credentialRequest = try issuanceRequestSupplier()
switch credentialRequest {
case .single(let single):
let result = try await requester.placeIssuanceRequest(
let result = try await issuanceRequester.placeIssuanceRequest(
accessToken: token,
request: single
)
Expand All @@ -349,7 +363,7 @@ private extension Issuer {
return handleIssuanceError(error)
}
case .batch(let credentials):
let result = try await requester.placeBatchIssuanceRequest(
let result = try await issuanceRequester.placeBatchIssuanceRequest(
accessToken: token,
request: credentials
)
Expand Down Expand Up @@ -484,7 +498,7 @@ public extension Issuer {
throw ValidationError.error(reason: "Invalid access token")
}

return try await requester.placeDeferredCredentialRequest(
return try await deferredIssuanceRequester.placeDeferredCredentialRequest(
accessToken: token,
transactionId: transactionId
)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Main/Authorisers/IssuanceAuthorizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public actor IssuanceAuthorizer: IssuanceAuthorizerType {
)
}
} catch {
return .failure(ValidationError.error(reason: error.localizedDescription))
return .failure(error)
}
}

Expand Down
Loading