...
1 package cosesign1
2
3 import (
4 "crypto/sha256"
5 "crypto/x509"
6 "encoding/base64"
7 "encoding/pem"
8 "errors"
9 "fmt"
10 "net/url"
11 "strings"
12
13 didx509resolver "github.com/Microsoft/hcsshim/internal/did-x509-resolver"
14 "github.com/sirupsen/logrus"
15 )
16
17 func parsePemChain(chainPem string) ([]*x509.Certificate, error) {
18 var chain = []*x509.Certificate{}
19
20 bs := []byte(chainPem)
21 for block, rest := pem.Decode(bs); block != nil; block, rest = pem.Decode(rest) {
22 if block.Type == "CERTIFICATE" {
23 cert, err := x509.ParseCertificate(block.Bytes)
24 if err != nil {
25 return nil, fmt.Errorf("certificate parser failed: %w", err)
26 }
27 chain = append(chain, cert)
28 }
29 }
30
31 return chain, nil
32 }
33
34 func MakeDidX509(fingerprintAlgorithm string, fingerprintIndex int, chainPEM string, didPolicy string, verbose bool) (string, error) {
35 if fingerprintAlgorithm != "sha256" {
36 return "", fmt.Errorf("unsupported fingerprint hash algorithm %q", fingerprintAlgorithm)
37 }
38
39 if fingerprintIndex < 1 {
40 return "", fmt.Errorf("fingerprint index must be >= 1")
41 }
42
43 chain, err := parsePemChain(chainPEM)
44 if err != nil {
45 return "", err
46 }
47
48 if len(chain) < 1 {
49 return "", fmt.Errorf("chain must not be empty")
50 }
51
52 if fingerprintIndex > len(chain)-1 {
53 return "", fmt.Errorf("signer index out of bounds")
54 }
55
56 signerCert := chain[fingerprintIndex]
57 hash := sha256.Sum256(signerCert.Raw)
58 fingerprint := base64.RawURLEncoding.EncodeToString(hash[:])
59
60 var policyTokens []string
61 didPolicyUpper := strings.ToUpper(didPolicy)
62 switch didPolicyUpper {
63 case "CN":
64 policyTokens = append(policyTokens, "subject", "CN", chain[0].Subject.CommonName)
65 case "EKU":
66
67
68
69
70
71 if len(chain[0].UnknownExtKeyUsage) > 0 {
72 policyTokens = append(policyTokens, "eku", chain[0].UnknownExtKeyUsage[0].String())
73 } else if len(chain[0].ExtKeyUsage) > 0 {
74 extendedKeyUsage := chain[0].ExtKeyUsage[0]
75 keyUsageOid, ok := didx509resolver.OidFromExtKeyUsage(extendedKeyUsage)
76
77 if ok {
78 policyTokens = append(policyTokens, "eku", keyUsageOid.String())
79 }
80 }
81 default:
82
83 policyTokens = strings.Split(didPolicy, ":")
84 }
85
86 if len(policyTokens) == 0 {
87 return "", errors.New("invalid policy")
88 }
89
90 for i := 0; i < len(policyTokens); i++ {
91 policyName := policyTokens[i]
92 switch policyName {
93 case "subject":
94 i += 2
95 if i >= len(policyTokens) {
96 return "", fmt.Errorf("invalid %q policy", policyName)
97 }
98 policyTokens[i] = url.PathEscape(policyTokens[i])
99 default:
100 }
101 }
102
103 r := "did:x509:0:" + fingerprintAlgorithm + ":" + fingerprint + "::" + strings.Join(policyTokens, ":")
104 _, err = didx509resolver.Resolve(chainPEM, r, true)
105 if err != nil {
106 return "", err
107 }
108
109 if verbose {
110 logrus.Debug("did:x509 resolved correctly")
111 }
112
113 return r, nil
114 }
115
View as plain text