-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
vp: some initial start and added debug support to almost all services
- Loading branch information
1 parent
5699879
commit afb5a01
Showing
6 changed files
with
324 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Compile | ||
FROM docker.sunet.se/dc4eu/gobuild:latest AS builder | ||
|
||
# Build Delve | ||
RUN go install github.com/go-delve/delve/cmd/dlv@latest | ||
|
||
COPY . . | ||
ARG SERVICE_NAME | ||
|
||
RUN make swagger | ||
RUN make proto | ||
|
||
RUN --mount=type=cache,target=/root/.cache/go-build GOOS=linux GOARCH=amd64 go build -v -o bin/vc_$SERVICE_NAME -ldflags \ | ||
"-X vc/pkg/model.BuildVariableGitCommit=$(git rev-list -1 HEAD) \ | ||
-X vc/pkg/model.BuildVariableGitBranch=$(git rev-parse --abbrev-ref HEAD) \ | ||
-X vc/pkg/model.BuildVariableTimestamp=$(date +'%F:T%TZ') \ | ||
-X vc/pkg/model.BuildVariableGoVersion=$(go version|awk '{print $3}') \ | ||
-X vc/pkg/model.BuildVariableGoArch=$(go version|awk '{print $4}') \ | ||
-X vc/pkg/model.BuildVersion=$(git tag |tail -1) \ | ||
--extldflags '-static'" ./cmd/$SERVICE_NAME/main.go | ||
|
||
# Deploy | ||
FROM debian:bookworm-slim | ||
|
||
ARG SERVICE_NAME | ||
|
||
WORKDIR / | ||
|
||
RUN apt-get update && apt-get install -y curl procps iputils-ping less | ||
RUN rm -rf /var/lib/apt/lists/* | ||
|
||
COPY --from=builder /go/bin/dlv / | ||
COPY --from=builder /go/src/app/bin/vc_${SERVICE_NAME} /vc_service | ||
COPY --from=builder /go/src/app/docs /docs | ||
COPY --from=builder /go/src/app/standards /standards | ||
COPY --from=builder /go/src/app/users_paris.xlsx /users_paris.xlsx | ||
|
||
EXPOSE 8080 | ||
|
||
HEALTHCHECK --interval=20s --timeout=10s CMD curl --connect-timeout 5 http://localhost:8080/health | grep -q STATUS_OK | ||
|
||
# vars in CMD and ENTRYPOINT are evaluated at runtime, that's why we use a static name on the binary. | ||
CMD [ "./vc_service" ] | ||
|
||
EXPOSE 8080 40000 | ||
|
||
HEALTHCHECK --interval=20s --timeout=10s CMD curl --connect-timeout 5 http://localhost:8080/health | grep -q STATUS_OK | ||
|
||
# vars in CMD and ENTRYPOINT are evaluated at runtime, that's why we use a static name on the binary. | ||
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "./vc_service"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package apiv1 | ||
|
||
import ( | ||
"encoding/base64" | ||
"encoding/json" | ||
"errors" | ||
"strings" | ||
) | ||
|
||
// VPToken represents the structure for validating a Verifiable Presentation token. | ||
type VPToken struct { | ||
RawToken string // The raw input token | ||
Header map[string]interface{} // Decoded JWT header | ||
Payload map[string]interface{} // Decoded JWT payload | ||
Signature string // Extracted JWT signature | ||
//TODO(mk): gör en struct för nedan | ||
DecodedCredentials []map[string]interface{} // Decoded Verifiable Credentials | ||
//TODO(mk): gör en struct för nedan | ||
DisclosedClaims []string // Claims disclosed by the Holder | ||
//TODO(mk): gör en struct för nedan | ||
ValidationResults map[string]bool // Validation results for different steps | ||
} | ||
|
||
// NewVPToken initializes a new VPToken instance from a raw token. | ||
func NewVPToken(rawToken string) (*VPToken, error) { | ||
if rawToken == "" { | ||
return nil, errors.New("empty vp_token provided") | ||
} | ||
|
||
vp := &VPToken{ | ||
RawToken: rawToken, | ||
DecodedCredentials: make([]map[string]interface{}, 0), | ||
DisclosedClaims: make([]string, 0), | ||
ValidationResults: make(map[string]bool), | ||
} | ||
|
||
return vp, nil | ||
} | ||
|
||
// Validate runs the full validation process including extract and decode. | ||
func (vp *VPToken) Validate() error { | ||
|
||
// 1. Extracts And decodes the VP token into its components | ||
if err := vp.extractAndDecode(); err != nil { | ||
return err | ||
} | ||
|
||
// 2. Verify Holder's Signature | ||
// Verify the signature of the outer JWT using the Holder's public key. | ||
if err := vp.validateHolderSignature(); err != nil { | ||
return err | ||
} | ||
|
||
// 3. Validate Issuer's Signatures on Embedded VC's | ||
// Extract and verify the signatures of all Verifiable Credentials using the Issuer's public key. | ||
if err := vp.validateIssuerSignatures(); err != nil { | ||
return err | ||
} | ||
|
||
// 4. Check Credential Validity for each VC | ||
// Ensure that credentials are not expired, revoked, or issued by untrusted issuers. | ||
if err := vp.validateCredentials(); err != nil { | ||
return err | ||
} | ||
|
||
// 5. Verify Selective Disclosure Claims | ||
// Validate disclosed claims against the hashed values in the original credential. | ||
if err := vp.verifySelectiveDisclosure(); err != nil { | ||
return err | ||
} | ||
|
||
// 6. Validate Holder Binding | ||
// Ensure the Holder is correctly bound to the credential. | ||
if err := vp.validateHolderBinding(); err != nil { | ||
return err | ||
} | ||
|
||
// 7. Validate Presentation Requirements | ||
// Ensure the VP matches the verifier's requirements. | ||
return vp.validatePresentationRequirements() | ||
} | ||
|
||
// extractAndDecode extracts and decodes the VP token into its components: header, payload, and signature. | ||
// Validates its basic structure to ensure it conforms to the JWT standard. | ||
func (vp *VPToken) extractAndDecode() error { | ||
tokenParts := strings.Split(vp.RawToken, ".") | ||
if len(tokenParts) != 3 { | ||
return errors.New("invalid token structure") | ||
} | ||
|
||
header, payload, signature := tokenParts[0], tokenParts[1], tokenParts[2] | ||
|
||
headerDecoded, err := decodeBase64URL(header) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
payloadDecoded, err := decodeBase64URL(payload) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
headerMap := make(map[string]interface{}) | ||
payloadMap := make(map[string]interface{}) | ||
|
||
if err := json.Unmarshal([]byte(headerDecoded), &headerMap); err != nil { | ||
return err | ||
} | ||
|
||
if err := json.Unmarshal([]byte(payloadDecoded), &payloadMap); err != nil { | ||
return err | ||
} | ||
|
||
vp.Header = headerMap | ||
vp.Payload = payloadMap | ||
vp.Signature = signature | ||
return nil | ||
} | ||
|
||
// validateHolderSignature verifies the signature of the outer JWT. | ||
func (vp *VPToken) validateHolderSignature() error { | ||
// Placeholder for holder signature validation logic. | ||
// Typically involves extracting JWK from payload and verifying signature. | ||
vp.ValidationResults["HolderSignature"] = true | ||
return nil | ||
} | ||
|
||
// validateIssuerSignatures validates signatures of all embedded Verifiable Credentials. | ||
func (vp *VPToken) validateIssuerSignatures() error { | ||
// Placeholder for issuer signature validation logic. | ||
// Extract VCs and validate their signatures using Issuer public keys. | ||
vp.ValidationResults["IssuerSignatures"] = true | ||
return nil | ||
} | ||
|
||
// validateCredentials checks the validity of the credentials. | ||
func (vp *VPToken) validateCredentials() error { | ||
// Placeholder for checking credential validity (e.g., expiration, revocation). | ||
vp.ValidationResults["Credentials"] = true | ||
return nil | ||
} | ||
|
||
// verifySelectiveDisclosure validates selective disclosure claims. | ||
func (vp *VPToken) verifySelectiveDisclosure() error { | ||
// Placeholder for validating _sd claims in the payload. | ||
vp.ValidationResults["SelectiveDisclosure"] = true | ||
return nil | ||
} | ||
|
||
// validateHolderBinding ensures the Holder is bound to the credential. | ||
func (vp *VPToken) validateHolderBinding() error { | ||
// Placeholder for validating Holder binding logic. | ||
vp.ValidationResults["HolderBinding"] = true | ||
return nil | ||
} | ||
|
||
// validatePresentationRequirements ensures the VP matches the verifier's requirements. | ||
func (vp *VPToken) validatePresentationRequirements() error { | ||
// Placeholder for matching claims with verifier requirements. | ||
vp.ValidationResults["PresentationRequirements"] = true | ||
return nil | ||
} | ||
|
||
// decodeBase64URL decodes a Base64URL-encoded string. | ||
func (vp *VPToken) decodeBase64URL(input string) ([]byte, error) { | ||
decoded, err := base64.RawURLEncoding.DecodeString(input) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return decoded, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package apiv1 | ||
|
||
import "testing" | ||
|
||
func TestVPToken_validateHolderSignature(t *testing.T) { | ||
type fields struct { | ||
RawToken string | ||
Header map[string]interface{} | ||
Payload map[string]interface{} | ||
Signature string | ||
DecodedCredentials []map[string]interface{} | ||
DisclosedClaims []string | ||
ValidationResults map[string]bool | ||
} | ||
tests := []struct { | ||
name string | ||
fields fields | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "Valid Holder Signature", | ||
fields: fields{ | ||
RawToken: `eyJhbGciOiAiRVMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiaG9sZGVyIiwgImF1ZCI6ICJ2ZXJpZmllciIsICJpYXQiOiAxNjgwODk3ODU1fQ.VALID_SIGNATURE`, | ||
Header: map[string]interface{}{ | ||
"alg": "ES256", | ||
"typ": "JWT", | ||
}, | ||
Payload: map[string]interface{}{ | ||
"sub": "holder", | ||
"aud": "verifier", | ||
"iat": 1680897855, | ||
}, | ||
Signature: "VALID_SIGNATURE", | ||
ValidationResults: map[string]bool{ | ||
"HolderSignature": false, | ||
}, | ||
}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "Invalid Holder Signature", | ||
fields: fields{ | ||
RawToken: `eyJhbGciOiAiRVMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiaG9sZGVyIiwgImF1ZCI6ICJ2ZXJpZmllciIsICJpYXQiOiAxNjgwODk3ODU1fQ.INVALID_SIGNATURE`, | ||
Header: map[string]interface{}{ | ||
"alg": "ES256", | ||
"typ": "JWT", | ||
}, | ||
Payload: map[string]interface{}{ | ||
"sub": "holder", | ||
"aud": "verifier", | ||
"iat": 1680897855, | ||
}, | ||
Signature: "INVALID_SIGNATURE", | ||
ValidationResults: map[string]bool{ | ||
"HolderSignature": false, | ||
}, | ||
}, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
vp := &VPToken{ | ||
RawToken: tt.fields.RawToken, | ||
Header: tt.fields.Header, | ||
Payload: tt.fields.Payload, | ||
Signature: tt.fields.Signature, | ||
DecodedCredentials: tt.fields.DecodedCredentials, | ||
DisclosedClaims: tt.fields.DisclosedClaims, | ||
ValidationResults: tt.fields.ValidationResults, | ||
} | ||
if err := vp.validateHolderSignature(); (err != nil) != tt.wantErr { | ||
t.Errorf("validateHolderSignature() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
}) | ||
} | ||
} |