Repository: hyperledger/aries-framework-go (go)

Issue:
Move cnf and _sd_alg to vc level
Move cnf and _sd_alg from credential subject level to vc level


Pull request description:
fix: Move cnf and _sd_alg to vc level
Move cnf and _sd_alg from credential subject level to vc level

Closes #3494

Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>




Patch:
diff --git a/pkg/doc/sdjwt/common/common.go b/pkg/doc/sdjwt/common/common.go
index b87b93e3..6622366c 100644
--- a/pkg/doc/sdjwt/common/common.go
+++ b/pkg/doc/sdjwt/common/common.go
@@ -272,8 +272,8 @@ func GetSDAlg(claims map[string]interface{}) (string, error) {
 
 	obj, ok := claims[SDAlgorithmKey]
 	if !ok {
-		// if claims contain 'vc' claim it may be present in credential subject
-		obj, ok = GetKeyFromCredentialSubject(SDAlgorithmKey, claims)
+		// if claims contain 'vc' claim it may be present in vc
+		obj, ok = GetKeyFromVC(SDAlgorithmKey, claims)
 		if !ok {
 			return "", fmt.Errorf("%s must be present in SD-JWT", SDAlgorithmKey)
 		}
@@ -287,28 +287,8 @@ func GetSDAlg(claims map[string]interface{}) (string, error) {
 	return alg, nil
 }
 
-// GetKeyFromCredentialSubject returns key value from VC credential subject.
-func GetKeyFromCredentialSubject(key string, claims map[string]interface{}) (interface{}, bool) {
-	csObj, ok := GetCredentialSubject(claims)
-	if !ok {
-		return nil, false
-	}
-
-	cs, ok := csObj.(map[string]interface{})
-	if !ok {
-		return nil, false
-	}
-
-	obj, ok := cs[key]
-	if !ok {
-		return nil, false
-	}
-
-	return obj, true
-}
-
-// GetCredentialSubject returns credential subject from vc.
-func GetCredentialSubject(claims map[string]interface{}) (interface{}, bool) {
+// GetKeyFromVC returns key value from VC.
+func GetKeyFromVC(key string, claims map[string]interface{}) (interface{}, bool) {
 	vcObj, ok := claims["vc"]
 	if !ok {
 		return nil, false
@@ -319,19 +299,19 @@ func GetCredentialSubject(claims map[string]interface{}) (interface{}, bool) {
 		return nil, false
 	}
 
-	csObj, ok := vc["credentialSubject"]
+	obj, ok := vc[key]
 	if !ok {
 		return nil, false
 	}
 
-	return csObj, true
+	return obj, true
 }
 
 // GetCNF returns confirmation claim 'cnf'.
 func GetCNF(claims map[string]interface{}) (map[string]interface{}, error) {
 	obj, ok := claims[CNFKey]
 	if !ok {
-		obj, ok = GetKeyFromCredentialSubject(CNFKey, claims)
+		obj, ok = GetKeyFromVC(CNFKey, claims)
 		if !ok {
 			return nil, fmt.Errorf("%s must be present in SD-JWT", CNFKey)
 		}
diff --git a/pkg/doc/sdjwt/issuer/issuer.go b/pkg/doc/sdjwt/issuer/issuer.go
index 4b357d9e..0e480580 100644
--- a/pkg/doc/sdjwt/issuer/issuer.go
+++ b/pkg/doc/sdjwt/issuer/issuer.go
@@ -32,6 +32,9 @@ const (
 
 	decoyMinElements = 1
 	decoyMaxElements = 4
+
+	credentialSubjectKey = "credentialSubject"
+	vcKey                = "vc"
 )
 
 var mr = mathrand.New(mathrand.NewSource(time.Now().Unix())) // nolint:gochecknoglobals
@@ -186,7 +189,7 @@ func New(issuer string, claims interface{}, headers jose.Headers,
 // NewFromVC creates new signed Selective Disclosure JWT based on vc.
 func NewFromVC(vc map[string]interface{}, headers jose.Headers,
 	signer jose.Signer, opts ...NewOpt) (*SelectiveDisclosureJWT, error) {
-	csObj, ok := common.GetCredentialSubject(vc)
+	csObj, ok := common.GetKeyFromVC(credentialSubjectKey, vc)
 	if !ok {
 		return nil, fmt.Errorf("credential subject not found")
 	}
@@ -208,8 +211,19 @@ func NewFromVC(vc map[string]interface{}, headers jose.Headers,
 		return nil, err
 	}
 
+	// move _sd_alg key from credential subject to vc as per example 4 in spec
+	vc[vcKey].(map[string]interface{})[common.SDAlgorithmKey] = selectiveCredentialSubject[common.SDAlgorithmKey]
+	delete(selectiveCredentialSubject, common.SDAlgorithmKey)
+
+	// move cnf key from credential subject to vc as per example 4 in spec
+	cnfObj, ok := selectiveCredentialSubject[common.CNFKey]
+	if ok {
+		vc[vcKey].(map[string]interface{})[common.CNFKey] = cnfObj
+		delete(selectiveCredentialSubject, common.CNFKey)
+	}
+
 	// update VC with 'selective' credential subject
-	vc["vc"].(map[string]interface{})["credentialSubject"] = selectiveCredentialSubject
+	vc[vcKey].(map[string]interface{})[credentialSubjectKey] = selectiveCredentialSubject
 
 	// sign VC with 'selective' credential subject
 	signedJWT, err := afgjwt.NewSigned(vc, nil, signer)


Test patch:
diff --git a/pkg/doc/sdjwt/common/common_test.go b/pkg/doc/sdjwt/common/common_test.go
index 1f058e9f..2dcac8cb 100644
--- a/pkg/doc/sdjwt/common/common_test.go
+++ b/pkg/doc/sdjwt/common/common_test.go
@@ -463,9 +463,7 @@ func TestGetSDAlg(t *testing.T) {
 		claims := map[string]interface{}{
 			"given_name": "John",
 			"vc": map[string]interface{}{
-				"credentialSubject": map[string]interface{}{
-					"_sd_alg": "sha-256",
-				},
+				"_sd_alg": "sha-256",
 			},
 		}
 
@@ -474,7 +472,7 @@ func TestGetSDAlg(t *testing.T) {
 		r.Equal("sha-256", alg)
 	})
 
-	t.Run("error - algorithm not found (empty claims)", func(t *testing.T) {
+	t.Run("error - algorithm not found (no vc)", func(t *testing.T) {
 		alg, err := GetSDAlg(make(map[string]interface{}))
 		r.Error(err)
 		r.Empty(alg)
@@ -482,13 +480,9 @@ func TestGetSDAlg(t *testing.T) {
 		r.Contains(err.Error(), "_sd_alg must be present in SD-JWT")
 	})
 
-	t.Run("error - algorithm not found", func(t *testing.T) {
+	t.Run("error - algorithm not found (vc is empty)", func(t *testing.T) {
 		claims := map[string]interface{}{
-			"vc": map[string]interface{}{
-				"credentialSubject": map[string]interface{}{
-					"given_name": "John",
-				},
-			},
+			"vc": map[string]interface{}{},
 		}
 
 		alg, err := GetSDAlg(claims)
@@ -498,7 +492,7 @@ func TestGetSDAlg(t *testing.T) {
 		r.Contains(err.Error(), "_sd_alg must be present in SD-JWT")
 	})
 
-	t.Run("error - algorithm not found (vc claim is not a map)", func(t *testing.T) {
+	t.Run("error - algorithm not found (vc is not a map)", func(t *testing.T) {
 		claims := map[string]interface{}{
 			"vc": "invalid",
 		}
@@ -510,40 +504,10 @@ func TestGetSDAlg(t *testing.T) {
 		r.Contains(err.Error(), "_sd_alg must be present in SD-JWT")
 	})
 
-	t.Run("error - algorithm not found (no credential subject in vc)", func(t *testing.T) {
-		claims := map[string]interface{}{
-			"vc": map[string]interface{}{
-				"id": "test-id",
-			},
-		}
-
-		alg, err := GetSDAlg(claims)
-		r.Error(err)
-		r.Empty(alg)
-
-		r.Contains(err.Error(), "_sd_alg must be present in SD-JWT")
-	})
-
-	t.Run("error - algorithm not found (credential subject is not a map)", func(t *testing.T) {
-		claims := map[string]interface{}{
-			"vc": map[string]interface{}{
-				"credentialSubject": "invalid",
-			},
-		}
-
-		alg, err := GetSDAlg(claims)
-		r.Error(err)
-		r.Empty(alg)
-
-		r.Contains(err.Error(), "_sd_alg must be present in SD-JWT")
-	})
-
 	t.Run("error - algorithm must be a string", func(t *testing.T) {
 		claims := map[string]interface{}{
 			"vc": map[string]interface{}{
-				"credentialSubject": map[string]interface{}{
-					"_sd_alg": 123,
-				},
+				"_sd_alg": 123,
 			},
 		}
 
@@ -585,7 +549,7 @@ func TestGetCNF(t *testing.T) {
 		r.NotEmpty(cnf["jwk"])
 	})
 
-	t.Run("success - cnf is in VC credential subject", func(t *testing.T) {
+	t.Run("success - cnf is in VC", func(t *testing.T) {
 		var payload map[string]interface{}
 
 		err := json.Unmarshal([]byte(vcSample), &payload)
@@ -662,16 +626,16 @@ const vcSample = `
 				"goPn0hokFnQBktqzXxgTK-4CCldmLjlRwUVCIltDyRg",
 				"FAiNODIxDMwGTljNYcVKkx7LBsr1pb-U6XuAfVFuOGY"
 			],
-			"_sd_alg": "sha-256",
-			"cnf": {
-				"jwk": {
-					"crv": "Ed25519",
-					"kty": "OKP",
-					"x": "7jtkxxk0Pb3E0O6JXJiN8HyIp2DpCiqaHCWfMXl9ZFo"
-				}
-			},
 			"id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
 		},
+		"_sd_alg": "sha-256",
+		"cnf": {
+			"jwk": {
+				"crv": "Ed25519",
+				"kty": "OKP",
+				"x": "7jtkxxk0Pb3E0O6JXJiN8HyIp2DpCiqaHCWfMXl9ZFo"
+			}
+		},
 		"first_name": "First name",
 		"id": "http://example.edu/credentials/1872",
 		"info": "Info",
diff --git a/pkg/doc/sdjwt/holder/holder_test.go b/pkg/doc/sdjwt/holder/holder_test.go
index ac01a111..c5ba38e3 100644
--- a/pkg/doc/sdjwt/holder/holder_test.go
+++ b/pkg/doc/sdjwt/holder/holder_test.go
@@ -74,7 +74,7 @@ func TestParse(t *testing.T) {
 		claims, err := Parse(vcCombinedFormatForIssuance, WithSignatureVerifier(&NoopSignatureVerifier{}))
 		r.NoError(err)
 		require.NotNil(t, claims)
-		require.Equal(t, 3, len(claims))
+		require.Equal(t, 4, len(claims))
 	})
 
 	t.Run("success - complex claims", func(t *testing.T) {
@@ -290,4 +290,5 @@ const additionalDisclosure = `WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwgImdpdmVuX25hbW
 // nolint: lll
 const specSDJWT = `eyJhbGciOiAiUlMyNTYiLCAia2lkIjogImNBRUlVcUowY21MekQxa3pHemhlaUJhZzBZUkF6VmRsZnhOMjgwTmdIYUEifQ.eyJfc2QiOiBbIk5ZQ29TUktFWXdYZHBlNXlkdUpYQ3h4aHluRVU4ei1iNFR5TmlhcDc3VVkiLCAiU1k4bjJCYmtYOWxyWTNleEhsU3dQUkZYb0QwOUdGOGE5Q1BPLUc4ajIwOCIsICJUUHNHTlBZQTQ2d21CeGZ2MnpuT0poZmRvTjVZMUdrZXpicGFHWkNUMWFjIiwgIlprU0p4eGVHbHVJZFlCYjdDcWtaYkpWbTB3MlY1VXJSZU5UekFRQ1lCanciLCAibDlxSUo5SlRRd0xHN09MRUlDVEZCVnhtQXJ3OFBqeTY1ZEQ2bXRRVkc1YyIsICJvMVNBc0ozM1lNaW9POXBYNVZlQU0xbHh1SEY2aFpXMmtHZGtLS0JuVmxvIiwgInFxdmNxbmN6QU1nWXg3RXlrSTZ3d3RzcHl2eXZLNzkwZ2U3TUJiUS1OdXMiXSwgImlzcyI6ICJodHRwczovL2V4YW1wbGUuY29tL2lzc3VlciIsICJpYXQiOiAxNTE2MjM5MDIyLCAiZXhwIjogMTUxNjI0NzAyMiwgIl9zZF9hbGciOiAic2hhLTI1NiIsICJjbmYiOiB7Imp3ayI6IHsia3R5IjogIlJTQSIsICJuIjogInBtNGJPSEJnLW9ZaEF5UFd6UjU2QVdYM3JVSVhwMTFfSUNEa0dnUzZXM1pXTHRzLWh6d0kzeDY1NjU5a2c0aFZvOWRiR29DSkUzWkdGX2VhZXRFMzBVaEJVRWdwR3dyRHJRaUo5enFwcm1jRmZyM3F2dmtHanR0aDhaZ2wxZU0yYkpjT3dFN1BDQkhXVEtXWXMxNTJSN2c2SmcyT1ZwaC1hOHJxLXE3OU1oS0c1UW9XX21UejEwUVRfNkg0YzdQaldHMWZqaDhocFdObmJQX3B2NmQxelN3WmZjNWZsNnlWUkwwRFYwVjNsR0hLZTJXcWZfZU5HakJyQkxWa2xEVGs4LXN0WF9NV0xjUi1FR21YQU92MFVCV2l0U19kWEpLSnUtdlhKeXcxNG5IU0d1eFRJSzJoeDFwdHRNZnQ5Q3N2cWltWEtlRFRVMTRxUUwxZUU3aWhjdyIsICJlIjogIkFRQUIifX19.xqgKrDO6dK_oBL3fiqdcq_elaIGxM6Z-RyuysglGyddR1O1IiE3mIk8kCpoqcRLR88opkVWN2392K_XYfAuAmeT9kJVisD8ZcgNcv-MQlWW9s8WaViXxBRe7EZWkWRQcQVR6jf95XZ5H2-_KA54POq3L42xjk0y5vDr8yc08Reak6vvJVvjXpp-Wk6uxsdEEAKFspt_EYIvISFJhfTuQqyhCjnaW13X312MSQBPwjbHn74ylUqVLljDvqcemxeqjh42KWJq4C3RqNJ7anA2i3FU1kB4-KNZWsijY7-op49iL7BrnIBxdlAMrbHEkoGTbFWdl7Ki17GHtDxxa1jaxQg~WyJkcVR2WE14UzBHYTNEb2FHbmU5eDBRIiwgInN1YiIsICJqb2huX2RvZV80MiJd~WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJxUVdtakpsMXMxUjRscWhFTkxScnJ3IiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyJLVXhTNWhFX1hiVmFjckdBYzdFRnd3IiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyIzcXZWSjFCQURwSERTUzkzOVEtUml3IiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyIweEd6bjNNaXFzY3RaSV9PcERsQWJRIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJFUktNMENOZUZKa2FENW1UWFZfWDh3IiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0`
 
-const vcCombinedFormatForIssuance = `eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp0cnVzdGJsb2M6YWJjI2tleTEifQ.eyJpYXQiOjE2NzM5ODc1NDcsImlzcyI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImp0aSI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwibmJmIjoxNjczOTg3NTQ3LCJzdWIiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJfc2QiOlsiVklMLXlXZHlZX3hNbk5icEJvbHRrcnlBOFZESVFVYllLd2dQaHVEUEx1ZyIsIkxDLUg0R2N4UG1OdGN5VWNiSGFDbTlEUDFnZDROYXJsZ2RiUFc4ZEVvZ2siLCJlbHVRRFVtbHpwM19naU9uRFVRVk1WLWpWM1hMNXVIck1BNzRROXI0dVF3Il0sIl9zZF9hbGciOiJzaGEtMjU2IiwiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEifSwiZmlyc3RfbmFtZSI6IkZpcnN0IG5hbWUiLCJpZCI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwiaW5mbyI6IkluZm8iLCJpc3N1YW5jZURhdGUiOiIyMDIzLTAxLTE3VDIyOjMyOjI3LjQ2ODEwOTgxNyswMjowMCIsImlzc3VlciI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImxhc3RfbmFtZSI6Ikxhc3QgbmFtZSIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCJ9fQ.PvRYW8-EAG7K4QQL3TV-GNF--vaYIGc3TWJrRSoc2qBCVT5sFkez7FTLv7iae24S2mi2GH5lcxy1dx75LSjOBA~WyJIb01DbEdxLUpRUUZIMUVZZnFCN1FBIiwic3BvdXNlIiwiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIl0~WyI5ZDFzTUFYUEVTZkEzaTE0NDNzVTRRIiwiZGVncmVlIix7ImRlZ3JlZSI6Ik1JVCIsInR5cGUiOiJCYWNoZWxvckRlZ3JlZSJ9XQ~WyJiekpGY1pYMkYyRjE3XzVsSFU2MjF3IiwibmFtZSIsIkpheWRlbiBEb2UiXQ` // nolint: lll
+// nolint: lll
+const vcCombinedFormatForIssuance = `eyJhbGciOiJFZERTQSJ9.eyJpYXQiOjEuNjczOTg3NTQ3ZSswOSwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEuNjczOTg3NTQ3ZSswOSwic3ViIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiZDlYemtRbVJMQncxSXpfeHVGUmVLMUItRmpCdTdjT0N3RTlOR2F1d251SSJ9fSwiY3JlZGVudGlhbFN1YmplY3QiOnsiX3NkIjpbInBBdjJUMU10YmRXNGttUUdxT1VVRUpjQmdTZi1mSFRHV2xQVUV4aWlIbVEiLCI2dDlBRUJCQnEzalZwckJ3bGljOGhFWnNNSmxXSXhRdUw5c3ExMzJZTnYwIl0sImRlZ3JlZSI6eyJfc2QiOlsibzZzV2h4RjcxWHBvZ1cxVUxCbU90bjR1SXFGdjJ3ODF6emRuelJXdlpqYyIsIi1yRklXbU1YR3ZXX0FIYVEtODhpMy11ZzRUVjhLUTg5TjdmZmtneFc2X2MiXX0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIn0sImZpcnN0X25hbWUiOiJGaXJzdCBuYW1lIiwiaWQiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMTg3MiIsImluZm8iOiJJbmZvIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0wMS0xN1QyMjozMjoyNy40NjgxMDk4MTcrMDI6MDAiLCJpc3N1ZXIiOiJkaWQ6ZXhhbXBsZTo3NmUxMmVjNzEyZWJjNmYxYzIyMWViZmViMWYiLCJsYXN0X25hbWUiOiJMYXN0IG5hbWUiLCJ0eXBlIjoiVmVyaWZpYWJsZUNyZWRlbnRpYWwifX0.GcfSA6NkONxdsm5Lxj9-988eWx1ZvMz5vJ1uh2x8UK1iKIeQLmhsWpA_34RbtAm2HnuoxW4_ZGeiHBzQ1GLTDQ~WyJFWkVDRVZ1YWVJOXhZWmlWb3VMQldBIiwidHlwZSIsIkJhY2hlbG9yRGVncmVlIl0~WyJyMno1UzZMa25FRTR3TWwteFB0VEx3IiwiZGVncmVlIiwiTUlUIl0~WyJ2VkhfaGhNQy1aSUt5WFdtdDUyOWpnIiwic3BvdXNlIiwiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIl0~WyJrVzh0WVVwbVl1VmRoZktFT050TnFnIiwibmFtZSIsIkpheWRlbiBEb2UiXQ`
diff --git a/pkg/doc/sdjwt/integration_test.go b/pkg/doc/sdjwt/integration_test.go
index 2a79647d..ceda7a59 100644
--- a/pkg/doc/sdjwt/integration_test.go
+++ b/pkg/doc/sdjwt/integration_test.go
@@ -258,6 +258,7 @@ func TestSDJWTFlow(t *testing.T) {
 		printObject(t, "Verified Claims", verifiedClaims)
 	})
 
+	// TODO: This test will be deleted; you should use NewFromVC api for creating VC
 	t.Run("success - create VC plus holder binding", func(t *testing.T) {
 		holderPublicKey, holderPrivateKey, err := ed25519.GenerateKey(rand.Reader)
 		r.NoError(err)
@@ -297,8 +298,22 @@ func TestSDJWTFlow(t *testing.T) {
 		err = json.Unmarshal([]byte(sampleVC), &vc)
 		r.NoError(err)
 
+		const credentialSubjectKey = "credentialSubject"
+		const vcKey = "vc"
+
+		// move _sd_alg key from credential subject to vc as per example 4 in spec
+		vc[vcKey].(map[string]interface{})[common.SDAlgorithmKey] = selectiveCredentialSubject[common.SDAlgorithmKey]
+		delete(selectiveCredentialSubject, common.SDAlgorithmKey)
+
+		// move cnf key from credential subject to vc as per example 4 in spec
+		cnfObj, ok := selectiveCredentialSubject[common.CNFKey]
+		if ok {
+			vc[vcKey].(map[string]interface{})[common.CNFKey] = cnfObj
+			delete(selectiveCredentialSubject, common.CNFKey)
+		}
+
 		// update VC with 'selective' credential subject
-		vc["vc"].(map[string]interface{})["credentialSubject"] = selectiveCredentialSubject
+		vc[vcKey].(map[string]interface{})[credentialSubjectKey] = selectiveCredentialSubject
 
 		// sign VC with 'selective' credential subject
 		signedJWT, err := afjwt.NewSigned(vc, nil, signer)
@@ -371,6 +386,13 @@ func TestSDJWTFlow(t *testing.T) {
 			issuer.WithStructuredClaims(true))
 		r.NoError(err)
 
+		var decoded map[string]interface{}
+
+		err = token.DecodeClaims(&decoded)
+		require.NoError(t, err)
+
+		printObject(t, "SD-JWT Payload", decoded)
+
 		vcCombinedFormatForIssuance, err := token.Serialize(false)
 		r.NoError(err)
 
diff --git a/pkg/doc/sdjwt/verifier/verifier_test.go b/pkg/doc/sdjwt/verifier/verifier_test.go
index de8781bb..89a2cdd4 100644
--- a/pkg/doc/sdjwt/verifier/verifier_test.go
+++ b/pkg/doc/sdjwt/verifier/verifier_test.go
@@ -832,5 +832,5 @@ func prettyPrint(msg []byte) (string, error) {
 
 const additionalDisclosure = `WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwgImdpdmVuX25hbWUiLCAiSm9obiJd`
 
-const vcCombinedFormatForIssuance = `eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp0cnVzdGJsb2M6YWJjI2tleTEifQ.eyJpYXQiOjE2NzM5ODc1NDcsImlzcyI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImp0aSI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwibmJmIjoxNjczOTg3NTQ3LCJzdWIiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJfc2QiOlsiVklMLXlXZHlZX3hNbk5icEJvbHRrcnlBOFZESVFVYllLd2dQaHVEUEx1ZyIsIkxDLUg0R2N4UG1OdGN5VWNiSGFDbTlEUDFnZDROYXJsZ2RiUFc4ZEVvZ2siLCJlbHVRRFVtbHpwM19naU9uRFVRVk1WLWpWM1hMNXVIck1BNzRROXI0dVF3Il0sIl9zZF9hbGciOiJzaGEtMjU2IiwiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEifSwiZmlyc3RfbmFtZSI6IkZpcnN0IG5hbWUiLCJpZCI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwiaW5mbyI6IkluZm8iLCJpc3N1YW5jZURhdGUiOiIyMDIzLTAxLTE3VDIyOjMyOjI3LjQ2ODEwOTgxNyswMjowMCIsImlzc3VlciI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImxhc3RfbmFtZSI6Ikxhc3QgbmFtZSIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCJ9fQ.PvRYW8-EAG7K4QQL3TV-GNF--vaYIGc3TWJrRSoc2qBCVT5sFkez7FTLv7iae24S2mi2GH5lcxy1dx75LSjOBA~WyJIb01DbEdxLUpRUUZIMUVZZnFCN1FBIiwic3BvdXNlIiwiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIl0~WyI5ZDFzTUFYUEVTZkEzaTE0NDNzVTRRIiwiZGVncmVlIix7ImRlZ3JlZSI6Ik1JVCIsInR5cGUiOiJCYWNoZWxvckRlZ3JlZSJ9XQ~WyJiekpGY1pYMkYyRjE3XzVsSFU2MjF3IiwibmFtZSIsIkpheWRlbiBEb2UiXQ` // nolint: lll
-const vcSDJWT = `eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDp0cnVzdGJsb2M6YWJjI2tleTEifQ.eyJpYXQiOjE2NzM5ODc1NDcsImlzcyI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImp0aSI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwibmJmIjoxNjczOTg3NTQ3LCJzdWIiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJfc2QiOlsiVklMLXlXZHlZX3hNbk5icEJvbHRrcnlBOFZESVFVYllLd2dQaHVEUEx1ZyIsIkxDLUg0R2N4UG1OdGN5VWNiSGFDbTlEUDFnZDROYXJsZ2RiUFc4ZEVvZ2siLCJlbHVRRFVtbHpwM19naU9uRFVRVk1WLWpWM1hMNXVIck1BNzRROXI0dVF3Il0sIl9zZF9hbGciOiJzaGEtMjU2IiwiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEifSwiZmlyc3RfbmFtZSI6IkZpcnN0IG5hbWUiLCJpZCI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwiaW5mbyI6IkluZm8iLCJpc3N1YW5jZURhdGUiOiIyMDIzLTAxLTE3VDIyOjMyOjI3LjQ2ODEwOTgxNyswMjowMCIsImlzc3VlciI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsImxhc3RfbmFtZSI6Ikxhc3QgbmFtZSIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCJ9fQ.PvRYW8-EAG7K4QQL3TV-GNF--vaYIGc3TWJrRSoc2qBCVT5sFkez7FTLv7iae24S2mi2GH5lcxy1dx75LSjOBA`                                                                                                                                                                                                                                                                                                   // nolint: lll
+const vcCombinedFormatForIssuance = `eyJhbGciOiJFZERTQSJ9.eyJpYXQiOjEuNjczOTg3NTQ3ZSswOSwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEuNjczOTg3NTQ3ZSswOSwic3ViIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiZDlYemtRbVJMQncxSXpfeHVGUmVLMUItRmpCdTdjT0N3RTlOR2F1d251SSJ9fSwiY3JlZGVudGlhbFN1YmplY3QiOnsiX3NkIjpbInBBdjJUMU10YmRXNGttUUdxT1VVRUpjQmdTZi1mSFRHV2xQVUV4aWlIbVEiLCI2dDlBRUJCQnEzalZwckJ3bGljOGhFWnNNSmxXSXhRdUw5c3ExMzJZTnYwIl0sImRlZ3JlZSI6eyJfc2QiOlsibzZzV2h4RjcxWHBvZ1cxVUxCbU90bjR1SXFGdjJ3ODF6emRuelJXdlpqYyIsIi1yRklXbU1YR3ZXX0FIYVEtODhpMy11ZzRUVjhLUTg5TjdmZmtneFc2X2MiXX0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIn0sImZpcnN0X25hbWUiOiJGaXJzdCBuYW1lIiwiaWQiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMTg3MiIsImluZm8iOiJJbmZvIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0wMS0xN1QyMjozMjoyNy40NjgxMDk4MTcrMDI6MDAiLCJpc3N1ZXIiOiJkaWQ6ZXhhbXBsZTo3NmUxMmVjNzEyZWJjNmYxYzIyMWViZmViMWYiLCJsYXN0X25hbWUiOiJMYXN0IG5hbWUiLCJ0eXBlIjoiVmVyaWZpYWJsZUNyZWRlbnRpYWwifX0.GcfSA6NkONxdsm5Lxj9-988eWx1ZvMz5vJ1uh2x8UK1iKIeQLmhsWpA_34RbtAm2HnuoxW4_ZGeiHBzQ1GLTDQ~WyJFWkVDRVZ1YWVJOXhZWmlWb3VMQldBIiwidHlwZSIsIkJhY2hlbG9yRGVncmVlIl0~WyJyMno1UzZMa25FRTR3TWwteFB0VEx3IiwiZGVncmVlIiwiTUlUIl0~WyJ2VkhfaGhNQy1aSUt5WFdtdDUyOWpnIiwic3BvdXNlIiwiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIl0~WyJrVzh0WVVwbVl1VmRoZktFT050TnFnIiwibmFtZSIsIkpheWRlbiBEb2UiXQ` // nolint: lll
+const vcSDJWT = `eyJhbGciOiJFZERTQSJ9.eyJpYXQiOjEuNjczOTg3NTQ3ZSswOSwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEuNjczOTg3NTQ3ZSswOSwic3ViIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiX3NkX2FsZyI6InNoYS0yNTYiLCJjbmYiOnsiandrIjp7ImNydiI6IkVkMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiZDlYemtRbVJMQncxSXpfeHVGUmVLMUItRmpCdTdjT0N3RTlOR2F1d251SSJ9fSwiY3JlZGVudGlhbFN1YmplY3QiOnsiX3NkIjpbInBBdjJUMU10YmRXNGttUUdxT1VVRUpjQmdTZi1mSFRHV2xQVUV4aWlIbVEiLCI2dDlBRUJCQnEzalZwckJ3bGljOGhFWnNNSmxXSXhRdUw5c3ExMzJZTnYwIl0sImRlZ3JlZSI6eyJfc2QiOlsibzZzV2h4RjcxWHBvZ1cxVUxCbU90bjR1SXFGdjJ3ODF6emRuelJXdlpqYyIsIi1yRklXbU1YR3ZXX0FIYVEtODhpMy11ZzRUVjhLUTg5TjdmZmtneFc2X2MiXX0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIn0sImZpcnN0X25hbWUiOiJGaXJzdCBuYW1lIiwiaWQiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMTg3MiIsImluZm8iOiJJbmZvIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0wMS0xN1QyMjozMjoyNy40NjgxMDk4MTcrMDI6MDAiLCJpc3N1ZXIiOiJkaWQ6ZXhhbXBsZTo3NmUxMmVjNzEyZWJjNmYxYzIyMWViZmViMWYiLCJsYXN0X25hbWUiOiJMYXN0IG5hbWUiLCJ0eXBlIjoiVmVyaWZpYWJsZUNyZWRlbnRpYWwifX0.GcfSA6NkONxdsm5Lxj9-988eWx1ZvMz5vJ1uh2x8UK1iKIeQLmhsWpA_34RbtAm2HnuoxW4_ZGeiHBzQ1GLTDQ`                                                                                                                                                                                                                                                                                                                        // nolint:lll