From a caller's perspective, simplify the steps needed to sign a payload with a key associated to a DID as much as possible.
Reduce the amount of did-specific boilerplate code needed to produce any type of signature using a BearerDID. currently, here are all the steps needed everywhere a BearerDID is used to sign something. This requires an implementer's neckbeard to be of significant length. certainly long enough to cause undesired chafing.
This problem actually exists in all of our SDKs at the moment and acts as a significant barrier for implementers attempting to implement functionality that requires signing something with a DID (e.g. tbdex messages)
[!IMPORTANT]
the changes in this PR provide quite a bit more optionality and defensive checks (specifically wrt verification method selection) than what's currently on main
Current Usage
No Options (aka default signer)
func main() {
bearerDID, err := didjwk.Create()
if err != nil {
panic(err)
}
sign, verificationMethod, err := bearerDID.GetSigner(nil)
if err != nil {
panic(err)
}
payload := []byte("hi")
signature, err := sign(payload)
if err != nil {
panic(err)
}
fmt.Printf("signature: %s\n", hex.EncodeToString(signature))
legit, err := dsa.Verify(payload, signature, *verificationMethod.PublicKeyJwk)
if err != nil {
panic(err)
}
if !legit {
panic("expected signature to be valid")
}
}
With Options (signer using a key with a specific purpose)
GetSigner returns a sign method that can be used to sign a payload using a key associated to the BearerDID. This function also returns the verification method needed to verify the signature.
Returning the verification method allows the caller to provide the signature's recipient with a reference to the verification method needed to verify the payload. This is often done by including the verification method id either alongside the signature or as part of the header in the case of JSON Web Signatures.
The verifier can dereference the verification method id to obtain the public key needed to verify the signature. This function optionally takes a Verification Method selector that can be used to select a specific verification method from the DID Document if desired. If no selector is provided, the payload will be signed with the key associated to the first verification method in the DID Document.
The selector can either be a Verification Method ID or a Purpose. If a Purpose is provided, the first verification method in the DID Document that has the provided purpose will be used to sign the payload.
The returned signer is a function that takes a byte payload and returns a byte signature.
Concerns
The potential complexity introduced may outweigh the cognitive overhead required to maintain the code added in this PR.
Benefits
DID specific code is isolated to the did package instead of spilling out into many other packages. this makes changing key selection strategies easier because we can change them in 1 place vs. 3 or 4 across more than 1 repo
it's kinda cool that in 15ish lines of code you can sign a payload using a key stored in an HSM based KMS
Goals
BearerDID
. currently, here are all the steps needed everywhere aBearerDID
is used to sign something. This requires an implementer's neckbeard to be of significant length. certainly long enough to cause undesired chafing.Current Usage
No Options (aka default signer)
With Options (signer using a key with a specific purpose)
BearerDID.GetSigner()
ExplanationGetSigner
returns asign
method that can be used to sign a payload using a key associated to theBearerDID
. This function also returns the verification method needed to verify the signature.Returning the verification method allows the caller to provide the signature's recipient with a reference to the verification method needed to verify the payload. This is often done by including the verification method id either alongside the signature or as part of the header in the case of JSON Web Signatures.
The verifier can dereference the verification method id to obtain the public key needed to verify the signature. This function optionally takes a Verification Method selector that can be used to select a specific verification method from the DID Document if desired. If no selector is provided, the payload will be signed with the key associated to the first verification method in the DID Document.
The selector can either be a Verification Method ID or a Purpose. If a Purpose is provided, the first verification method in the DID Document that has the provided purpose will be used to sign the payload.
The returned signer is a function that takes a byte payload and returns a byte signature.
Concerns
The potential complexity introduced may outweigh the cognitive overhead required to maintain the code added in this PR.
Benefits
did
package instead of spilling out into many other packages. this makes changing key selection strategies easier because we can change them in 1 place vs. 3 or 4 across more than 1 repo