Skip to content
Draft
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
3,927 changes: 3,927 additions & 0 deletions specifications/did-1.0.md

Large diffs are not rendered by default.

10,308 changes: 10,308 additions & 0 deletions specifications/json-ld11.md

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions specifications/update-specs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,23 @@ then
fi

URLS=(
# OpenID specifications
"https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html"
"https://openid.net/specs/openid-federation-1_0.html"
"https://www.w3.org/TR/vc-data-model-2.0/"
"https://www.w3.org/TR/vc-jose-cose/"
"https://fidescommunity.github.io/DIIP/"
"https://openid.net/specs/openid-connect-core-1_0.html"
"https://openid.net/specs/openid-connect-discovery-1_0.html"
"https://openid.net/specs/openid-connect-rpinitiated-1_0.html"
"https://openid.net/specs/openid-connect-frontchannel-1_0.html"
"https://openid.net/specs/openid-connect-backchannel-1_0.html"
# W3C specifications
"https://www.w3.org/TR/vc-data-model-2.0/"
"https://www.w3.org/TR/vc-jose-cose/"
"https://www.w3.org/TR/vc-imp-guide/"
"https://www.w3.org/TR/did-1.0/"
"https://www.w3.org/TR/vc-data-integrity/"
"https://www.w3.org/TR/json-ld11/"
# DIIP specifications
"https://fidescommunity.github.io/DIIP/"
)

# For each of the specifications, fetch the content from the URL and save it
Expand Down
1,833 changes: 1,833 additions & 0 deletions specifications/vc-data-integrity.md

Large diffs are not rendered by default.

948 changes: 948 additions & 0 deletions specifications/vc-imp-guide.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/Codebooks/AtContextsEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
enum AtContextsEnum: string
{
case W3Org2018CredentialsV1 = 'https://www.w3.org/2018/credentials/v1';

case W3OrgNsCredentialsV2 = 'https://www.w3.org/ns/credentials/v2';
}
10 changes: 10 additions & 0 deletions src/Codebooks/ClaimsEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ enum ClaimsEnum: string
// @context
case AtContext = '@context';

case AtDirection = '@direction';

case AtLanguage = '@language';

// @type
case AtType = '@type';

case AtValue = '@value';

// Authentication Context Class Reference
case Acr = 'acr';

Expand Down Expand Up @@ -447,6 +453,10 @@ enum ClaimsEnum: string

case UserinfoSigningAlgValuesSupported = 'userinfo_signing_alg_values_supported';

case ValidFrom = 'validFrom';

case ValidUntil = 'validUntil';

// VerifiableCredential
case Vc = 'vc';

Expand Down
20 changes: 18 additions & 2 deletions src/Codebooks/ContentTypesEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,27 @@ enum ContentTypesEnum: string
{
case ApplicationDcSdJwt = 'application/dc+sd-jwt';

case ApplicationJwt = 'application/jwt';

case ApplicationEntityStatementJwt = 'application/entity-statement+jwt';

case ApplicationJwt = 'application/jwt';

case ApplicationTrustMarkJwt = 'application/trust-mark+jwt';

case ApplicationTrustMarkStatusResponseJwt = 'application/trust-mark-status-response+jwt';

case ApplicationVc = 'application/vc';

case ApplicationVcCose = 'application/vc+cose';

case ApplicationVcJwt = 'application/vc+jwt';

case ApplicationVcSdJwt = 'application/vc+sd-jwt';

case ApplicationVp = 'application/vp';

case ApplicationVpCose = 'application/vp+cose';

case ApplicationVpJwt = 'application/vp+jwt';

case ApplicationVpSdJwt = 'application/vp+sd-jwt';
}
7 changes: 4 additions & 3 deletions src/Codebooks/CredentialFormatIdentifiersEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ enum CredentialFormatIdentifiersEnum: string
// VC signed as a JWT, not using JSON-LD
case JwtVcJson = 'jwt_vc_json';

// VC Data Model v2.0 secured with SD-JWT
// https://www.w3.org/TR/vc-jose-cose/#with-sd-jwt
case VcSdJwt = 'vc+sd-jwt';

// VC signed as a JWT, using JSON-LD
case JwtVcJsonLd = 'jwt_vc_json-ld';

Expand All @@ -22,7 +26,4 @@ enum CredentialFormatIdentifiersEnum: string

// IETF SD-JWT VC
case DcSdJwt = 'dc+sd-jwt';

// Deprecated identifier for IETF SD-JWT VC. Use 'dc+sd-jwt' instead.
case VcSdJwt = 'vc+sd-jwt';
}
12 changes: 12 additions & 0 deletions src/Factories/ClaimFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
use SimpleSAML\OpenID\ValueAbstracts\GenericClaim;
use SimpleSAML\OpenID\ValueAbstracts\JwksClaim;
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Factories\VcDataModelClaimFactory;
use SimpleSAML\OpenID\VerifiableCredentials\VcDataModel2\Factories\VcDataModel2ClaimFactory;

class ClaimFactory
{
protected FederationClaimFactory $federationClaimFactory;

protected VcDataModelClaimFactory $vcDataModelClaimFactory;

protected VcDataModel2ClaimFactory $vcDataModel2ClaimFactory;


public function __construct(
protected readonly Helpers $helpers,
Expand All @@ -43,6 +46,15 @@ public function forVcDataModel(): VcDataModelClaimFactory
}


public function forVcDataModel2(): VcDataModel2ClaimFactory
{
return $this->vcDataModel2ClaimFactory ??= new VcDataModel2ClaimFactory(
$this->helpers,
$this,
);
}


/**
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
*/
Expand Down
84 changes: 84 additions & 0 deletions src/ValueAbstracts/LanguageValueObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\OpenID\ValueAbstracts;

use JsonSerializable;
use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
use SimpleSAML\OpenID\Exceptions\InvalidValueException;

class LanguageValueObject implements JsonSerializable
{
/**
* @param non-empty-string $value
* @param non-empty-string|null $language
* @param 'ltr'|'rtl'|null $direction
* @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
*/
public function __construct(
protected readonly string $value,
protected readonly ?string $language = null,
protected readonly ?string $direction = null,
) {
if ($this->value === '0') {
throw new InvalidValueException('Language value object @value must be a non-empty string.');
}

if ($this->direction !== null && !in_array($this->direction, ['ltr', 'rtl'], true)) {
throw new InvalidValueException('Language value object @direction must be "ltr" or "rtl".');
}

if ($this->language === '0') {
throw new InvalidValueException('Language value object @language must be a non-empty string.');
}
}


/**
* @return non-empty-string
*/
public function getValue(): string
{
return $this->value;
}


/**
* @return non-empty-string|null
*/
public function getLanguage(): ?string
{
return $this->language;
}


/**
* @return 'ltr'|'rtl'|null
*/
public function getDirection(): ?string
{
return $this->direction;
}


/**
* @return array<string, string>
*/
public function jsonSerialize(): array
{
$result = [
ClaimsEnum::AtValue->value => $this->value,
];

if ($this->language !== null) {
$result[ClaimsEnum::AtLanguage->value] = $this->language;
}

if ($this->direction !== null) {
$result[ClaimsEnum::AtDirection->value] = $this->direction;
}

return $result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims;

use SimpleSAML\OpenID\ValueAbstracts\ClaimInterface;
use SimpleSAML\OpenID\ValueAbstracts\LanguageValueObject;

class LocalizableStringValue implements ClaimInterface
{
/**
* @param non-empty-string $claimName
*/
public function __construct(
protected readonly LanguageValueObject $languageValueObject,
protected readonly string $claimName,
) {
}


public function getName(): string
{
return $this->claimName;
}


public function getValue(): LanguageValueObject
{
return $this->languageValueObject;
}


/**
* @return array<string, string>
*/
public function jsonSerialize(): array
{
return $this->languageValueObject->jsonSerialize();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims;

use SimpleSAML\OpenID\Exceptions\VcDataModelException;
use SimpleSAML\OpenID\ValueAbstracts\ClaimInterface;

class LocalizableStringValueBag implements ClaimInterface
{
/** @var \SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\LocalizableStringValue[] */
protected array $values;


public function __construct(
LocalizableStringValue $firstValue,
LocalizableStringValue ...$values,
) {
$this->values = [$firstValue, ...$values];
}


/**
* @throws \SimpleSAML\OpenID\Exceptions\VcDataModelException
*/
public function getFirstValueOrFail(): LocalizableStringValue
{
return $this->values[0] ?? throw new VcDataModelException('No values found');
}


public function getName(): string
{
return $this->getFirstValueOrFail()->getName();
}


/**
* @return \SimpleSAML\OpenID\VerifiableCredentials\VcDataModel\Claims\LocalizableStringValue[]
*/
public function getValue(): array
{
return $this->values;
}


/**
* Get a value by language tag (optional language filtering).
*
* @param non-empty-string|null $language
*/
public function getValueByLanguage(?string $language = null): ?LocalizableStringValue
{
if ($language === null) {
// Return first value if no language specified
return $this->values[0] ?? null;
}

foreach ($this->values as $value) {
if ($value->getValue()->getLanguage() === $language) {
return $value;
}
}

return null;
}


/**
* @return array<array<string, string>>
*/
public function jsonSerialize(): array
{
return array_map(
fn(LocalizableStringValue $value): array => $value->jsonSerialize(),
$this->values,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ class VcAtContextClaimValue implements ClaimInterface
public function __construct(
protected readonly string $baseContext,
protected readonly array $otherContexts,
AtContextsEnum $expectedBaseContext = AtContextsEnum::W3Org2018CredentialsV1,
) {
if ($this->baseContext !== AtContextsEnum::W3Org2018CredentialsV1->value) {
if ($this->baseContext !== $expectedBaseContext->value) {
throw new VcDataModelException(sprintf(
'Invalid VC @context claim. Base context should be %s, %s given.',
AtContextsEnum::W3Org2018CredentialsV1->value,
$expectedBaseContext->value,
$this->baseContext,
));
}
Expand Down Expand Up @@ -64,7 +65,7 @@ public function getName(): string
*/
public function getValue(): array
{
return[
return [
$this->baseContext,
...$this->otherContexts,
];
Expand Down
Loading
Loading