Skip to content

Commit

Permalink
Use sha256 instead of sha512
Browse files Browse the repository at this point in the history
Move Hash function to package where it's used.
Make hash alg a constant
Use PS256 instead of PS512 for signing
  • Loading branch information
stevenvegt committed Dec 13, 2024
1 parent dcc0eed commit e2cf89b
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 138 deletions.
57 changes: 46 additions & 11 deletions did_x509/did_x509.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package did_x509

import (
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/base64"
"errors"
Expand All @@ -12,8 +15,39 @@ import (

"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/uzi-did-x509-issuer/x509_cert"
"golang.org/x/crypto/sha3"
)

type HashAlg string

const (
Sha1 HashAlg = "sha1"
Sha256 HashAlg = "sha256"
Sha384 HashAlg = "sha384"
Sha512 HashAlg = "sha512"
)

// Hash computes the hash of the input data using the specified algorithm.
// Supported algorithms include "sha1", "sha256", "sha384", and "sha512".
// Returns the computed hash as a byte slice or an error if the algorithm is not supported.
func Hash(data []byte, alg HashAlg) ([]byte, error) {
switch alg {
case Sha1:
sum := sha1.Sum(data)
return sum[:], nil
case Sha256:
sum := sha256.Sum256(data)
return sum[:], nil
case Sha384:
sum := sha3.Sum384(data)
return sum[:], nil
case Sha512:
sum := sha512.Sum512(data)
return sum[:], nil
}
return nil, fmt.Errorf("unsupported hash algorithm: %s", alg)
}

type X509Did struct {
Version string
RootCertificateHash string
Expand All @@ -23,35 +57,36 @@ type X509Did struct {

// FormatDid constructs a decentralized identifier (DID) from a certificate chain and an optional policy.
// It returns the formatted DID string or an error if the root certificate or hash calculation fails.
func FormatDid(caCert *x509.Certificate, policy ...string) (string, error) {
alg := "sha512"
rootHash, err := x509_cert.Hash(caCert.Raw, alg)
func FormatDid(issuerCert *x509.Certificate, hashAlg HashAlg, policy ...string) (*did.DID, error) {
issuerCertHash, err := Hash(issuerCert.Raw, hashAlg)
if err != nil {
return "", err
return nil, err
}
encodeToString := base64.RawURLEncoding.EncodeToString(rootHash)
fragments := []string{"did", "x509", "0", alg, encodeToString}
return strings.Join([]string{strings.Join(fragments, ":"), strings.Join(policy, "::")}, "::"), nil

encodeToString := base64.RawURLEncoding.EncodeToString(issuerCertHash)
fragments := []string{"did", "x509", "0", string(hashAlg), encodeToString}
didString := strings.Join([]string{strings.Join(fragments, ":"), strings.Join(policy, "::")}, "::")
return did.ParseDID(didString)
}

// CreateDid generates a Decentralized Identifier (DID) from a given certificate chain.
// It extracts the Unique Registration Address (URA) from the chain, creates a policy with it, and formats the DID.
// Returns the generated DID or an error if any step fails.
func CreateDid(signingCert, caCert *x509.Certificate, subjectAttributes []x509_cert.SubjectTypeName, types ...x509_cert.SanTypeName) (string, error) {
func CreateDid(signingCert, caCert *x509.Certificate, subjectAttributes []x509_cert.SubjectTypeName, types ...x509_cert.SanTypeName) (*did.DID, error) {
otherNames, err := x509_cert.SelectSanTypes(signingCert, types...)
if err != nil {
return "", err
return nil, err
}
policies := CreateOtherNamePolicies(otherNames)

subjectTypes, err := x509_cert.SelectSubjectTypes(signingCert, subjectAttributes...)
if err != nil {
return "", err
return nil, err
}

policies = append(policies, CreateSubjectPolicies(subjectTypes)...)

formattedDid, err := FormatDid(caCert, policies...)
formattedDid, err := FormatDid(caCert, Sha256, policies...)
return formattedDid, err
}

Expand Down
105 changes: 86 additions & 19 deletions did_x509/did_x509_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,82 @@
package did_x509

import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"encoding/base64"
"fmt"
"strings"
"testing"

"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/uzi-did-x509-issuer/x509_cert"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/sha3"
)

func TestHash(t *testing.T) {
sha1sum := sha1.Sum([]byte("test"))
sha256sum := sha256.Sum256([]byte("test"))
sha384sum := sha3.Sum384([]byte("test"))
sha512sum := sha512.Sum512([]byte("test"))
testCases := []struct {
name string
data []byte
alg HashAlg
hash []byte
error error
}{
{
name: "SHA1",
data: []byte("test"),
alg: Sha1,
hash: sha1sum[:],
},
{
name: "SHA256",
data: []byte("test"),
alg: Sha256,
hash: sha256sum[:],
},
{
name: "SHA384",
data: []byte("test"),
alg: Sha384,
hash: sha384sum[:],
},
{
name: "SHA512",
data: []byte("test"),
alg: Sha512,
hash: sha512sum[:],
},
{
name: "Unsupported",
data: []byte("test"),
alg: "unsupported",
hash: nil,
error: fmt.Errorf("unsupported hash algorithm: %s", "unsupported"),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
hash, err := Hash(tc.data, tc.alg)
if tc.error != nil {
if err.Error() != tc.error.Error() {
t.Errorf("unexpected error %v, want %v", err, tc.error)
}
}
if !bytes.Equal(hash, tc.hash) {
t.Errorf("unexpected hash %x, want %x", hash, tc.hash)
}
})
}
}

func TestPercentEncode(t *testing.T) {
tests := []struct {
input string
Expand Down Expand Up @@ -44,8 +111,8 @@ func TestCreateDidSingle(t *testing.T) {
t.Fatal(err)
}

alg := "sha512"
hash, err := x509_cert.Hash(rootCert.Raw, alg)
alg := Sha256
hash, err := Hash(rootCert.Raw, alg)
if err != nil {
t.Fatal(err)
}
Expand All @@ -56,7 +123,7 @@ func TestCreateDidSingle(t *testing.T) {
name string
fields fields
args args
want string
want did.DID
errMsg string
sanTypes []x509_cert.SanTypeName
subjectTypes []x509_cert.SubjectTypeName
Expand All @@ -65,39 +132,39 @@ func TestCreateDidSingle(t *testing.T) {
name: "Happy path",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING", "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":"),
want: did.MustParseDID(strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING", "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":")),
sanTypes: types,
errMsg: "",
},
{
name: "Happy path",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING"}, ":"),
want: did.MustParseDID(strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING"}, ":")),
sanTypes: []x509_cert.SanTypeName{x509_cert.SanTypeOtherName, x509_cert.SanTypePermanentIdentifierValue},
errMsg: "",
},
{
name: "Happy path",
name: "ok - with san othername",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING"}, ":"),
want: did.MustParseDID(strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING"}, ":")),
sanTypes: []x509_cert.SanTypeName{x509_cert.SanTypeOtherName},
errMsg: "",
},
{
name: "Happy path",
name: "ok - with san permanentIdentifier.value",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING"}, ":"),
want: did.MustParseDID(strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "permanentIdentifier.value", "A_PERMANENT_STRING"}, ":")),
sanTypes: []x509_cert.SanTypeName{x509_cert.SanTypePermanentIdentifierValue},
errMsg: "",
},
{
name: "Happy path",
name: "ok - with san permanentIdentifier.assigner",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":"),
want: did.MustParseDID(strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":")),
sanTypes: []x509_cert.SanTypeName{x509_cert.SanTypePermanentIdentifierAssigner},
errMsg: "",
},
Expand All @@ -115,7 +182,7 @@ func TestCreateDidSingle(t *testing.T) {
}
}

if got != tt.want {
if *got != tt.want {
t.Errorf("DefaultDidProcessor.CreateDid() = \n%v\n, want: \n%v\n", got, tt.want)
}
})
Expand All @@ -132,8 +199,8 @@ func TestCreateDidDouble(t *testing.T) {
t.Fatal(err)
}

alg := "sha512"
hash, err := x509_cert.Hash(rootCert.Raw, alg)
alg := Sha256
hash, err := Hash(rootCert.Raw, alg)
if err != nil {
t.Fatal(err)
}
Expand All @@ -155,31 +222,31 @@ func TestCreateDidDouble(t *testing.T) {
name: "Happy path san",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_SMALL_STRING", "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":"),
want: strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "san", "permanentIdentifier.value", "A_SMALL_STRING", "", "san", "permanentIdentifier.assigner", "2.16.528.1.1007.3.3"}, ":"),
sanTypes: sanTypeNames,
errMsg: "",
},
{
name: "Happy path short san",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING"}, ":"),
want: strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING"}, ":"),
sanTypes: sanTypeNamesShort,
errMsg: "",
},
{
name: "Happy path short san",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "subject", "O", "FauxCare"}, ":"),
want: strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "subject", "O", "FauxCare"}, ":"),
subjectTypes: subjectTypeNamesShort,
errMsg: "",
},
{
name: "Happy path mixed",
fields: fields{},
args: args{chain: chain},
want: strings.Join([]string{"did", "x509", "0", alg, rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "subject", "O", "FauxCare"}, ":"),
want: strings.Join([]string{"did", "x509", "0", string(alg), rootHashString, "", "san", "otherName", "A_BIG_STRING", "", "subject", "O", "FauxCare"}, ":"),
sanTypes: sanTypeNamesShort,
subjectTypes: subjectTypeNamesShort,
errMsg: "",
Expand All @@ -198,7 +265,7 @@ func TestCreateDidDouble(t *testing.T) {
}
}

if got != tt.want {
if got != nil && got.String() != tt.want {
t.Errorf("DefaultDidProcessor.CreateDid() = \n%v\n, want: \n%v\n", got, tt.want)
}
})
Expand Down
Loading

0 comments on commit e2cf89b

Please sign in to comment.