@@ -25,6 +25,24 @@ const (
25
25
26
26
var errrorInvalidAttestations = errors .New ("invalid npm attestations" )
27
27
28
+ /*
29
+ NOTE: key available at https://registry.npmjs.org/-/npm/v1/keys
30
+
31
+ https://docs.npmjs.com/about-registry-signatures
32
+ {
33
+ "keys": [
34
+ {
35
+ "expires": null,
36
+ "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
37
+ "keytype": "ecdsa-sha2-nistp256",
38
+ "scheme": "ecdsa-sha2-nistp256",
39
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
40
+ }
41
+ ]
42
+ }
43
+ */
44
+ var npmRegistryPublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
45
+
28
46
type attestation struct {
29
47
PredicateType string `json:"predicateType"`
30
48
BundleBytes BundleBytes `json:"bundle"`
@@ -63,28 +81,41 @@ func NpmNew(ctx context.Context, root *TrustedRoot, attestationBytes []byte) (*N
63
81
return nil , fmt .Errorf ("%w: json.Unmarshal: %v" , errrorInvalidAttestations , err )
64
82
}
65
83
66
- if len (attestations ) != 2 {
67
- return nil , fmt .Errorf ("%w: invalid number of attestations: %v" , errrorInvalidAttestations , len (attestations ))
84
+ prov , pub , err := extractAttestations (attestations )
85
+ if err != nil {
86
+ return nil , err
68
87
}
88
+ return & Npm {
89
+ ctx : ctx ,
90
+ root : root ,
91
+ provenanceAttestation : prov ,
92
+ publishAttestation : pub ,
93
+ }, nil
94
+ }
69
95
70
- // Attestation type verification.
71
- if attestations [0 ].PredicateType != slsaprovenance .ProvenanceV02Type {
72
- return nil , fmt .Errorf ("%w: invalid predicate type: %v. Expected %v" , errrorInvalidAttestations ,
73
- attestations [0 ].PredicateType , slsaprovenance .ProvenanceV02Type )
96
+ func extractAttestations (attestations []attestation ) (* attestation , * attestation , error ) {
97
+ if len (attestations ) < 2 {
98
+ return nil , nil , fmt .Errorf ("%w: invalid number of attestations: %v" , errrorInvalidAttestations , len (attestations ))
74
99
}
75
100
76
- // Provenance type verification.
77
- if ! strings .HasPrefix (attestations [1 ].PredicateType , publishAttestationV01 ) {
78
- return nil , fmt .Errorf ("%w: invalid predicate type: %v. Expected %v" , errrorInvalidAttestations ,
79
- attestations [1 ].PredicateType , publishAttestationV01 )
101
+ var provenanceAttestation * attestation
102
+ var publishAttestation * attestation
103
+ for i := range attestations {
104
+ att := attestations [i ]
105
+ // Provenance type verification.
106
+ if att .PredicateType == slsaprovenance .ProvenanceV02Type {
107
+ provenanceAttestation = & att
108
+ }
109
+ // Publish type verification.
110
+ if strings .HasPrefix (att .PredicateType , publishAttestationV01 ) {
111
+ publishAttestation = & att
112
+ }
80
113
}
81
114
82
- return & Npm {
83
- ctx : ctx ,
84
- root : root ,
85
- provenanceAttestation : & attestations [0 ],
86
- publishAttestation : & attestations [1 ],
87
- }, nil
115
+ if provenanceAttestation == nil || publishAttestation == nil {
116
+ return nil , nil , fmt .Errorf ("%w: invalid attestation types" , errrorInvalidAttestations )
117
+ }
118
+ return provenanceAttestation , publishAttestation , nil
88
119
}
89
120
90
121
func (n * Npm ) verifyProvenanceAttestationSignature () error {
@@ -122,24 +153,8 @@ func (n *Npm) verifyPublishAttesttationSignature() error {
122
153
// TODO(#496): verify the keyid, both in DSSE and hint.
123
154
124
155
// Verify the signature.
125
- /*
126
- NOTE: key available at https://registry.npmjs.org/-/npm/v1/keys
127
- https://docs.npmjs.com/about-registry-signatures
128
- {
129
- "keys": [
130
- {
131
- "expires": null,
132
- "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
133
- "keytype": "ecdsa-sha2-nistp256",
134
- "scheme": "ecdsa-sha2-nistp256",
135
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
136
- }
137
- ]
138
- }
139
- */
140
156
payloadHash := sha256 .Sum256 (payload )
141
- b64key := "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
142
- rawKey , err := base64 .StdEncoding .DecodeString (b64key )
157
+ rawKey , err := base64 .StdEncoding .DecodeString (npmRegistryPublicKey )
143
158
if err != nil {
144
159
return fmt .Errorf ("DecodeString: %w" , err )
145
160
}
@@ -320,7 +335,7 @@ func verifyProvenanceSubjectVersion(att *SignedAttestation, expectedVersion stri
320
335
return err
321
336
}
322
337
323
- subVersion , err := getPackageVersion (subject )
338
+ _ , subVersion , err := getPackageNameAndVersion (subject )
324
339
if err != nil {
325
340
return err
326
341
}
@@ -386,7 +401,7 @@ func verifyProvenanceSubjectName(att *SignedAttestation, expectedName string) er
386
401
}
387
402
388
403
func verifyName (actual , expected string ) error {
389
- subName , err := getPackageName (actual )
404
+ subName , _ , err := getPackageNameAndVersion (actual )
390
405
if err != nil {
391
406
return err
392
407
}
@@ -399,40 +414,26 @@ func verifyName(actual, expected string) error {
399
414
return nil
400
415
}
401
416
402
- func getPackageName (name string ) (string , error ) {
417
+ func getPackageNameAndVersion (name string ) (string , string , error ) {
418
+ var pkgname , pkgtag string
403
419
n := name
404
420
if strings .HasPrefix (name , "@" ) {
405
421
n = n [1 :]
406
422
}
407
423
parts := strings .Split (n , "@" )
408
424
if len (parts ) > 2 {
409
- return "" , fmt .Errorf ("%w: %v" , serrors .ErrorInvalidPackageName , name )
425
+ return "" , "" , fmt .Errorf ("%w: %v" , serrors .ErrorInvalidPackageName , name )
410
426
}
411
427
412
- pkgname : = parts [0 ]
428
+ pkgname = parts [0 ]
413
429
if strings .HasPrefix (name , "@" ) {
414
430
pkgname = "@" + pkgname
415
431
}
416
-
417
- return pkgname , nil
418
- }
419
-
420
- func getPackageVersion (name string ) (string , error ) {
421
- n := name
422
- if strings .HasPrefix (name , "@" ) {
423
- n = n [1 :]
424
- }
425
- parts := strings .Split (n , "@" )
426
- if len (parts ) > 2 {
427
- return "" , fmt .Errorf ("%w: %v" , serrors .ErrorInvalidPackageName , name )
428
- }
429
-
430
- var pkgtag string
431
432
if len (parts ) == 2 {
432
433
pkgtag = parts [1 ]
433
434
}
434
435
435
- return pkgtag , nil
436
+ return pkgname , pkgtag , nil
436
437
}
437
438
438
439
func getSubject (att * SignedAttestation ) (string , error ) {
@@ -462,7 +463,3 @@ func getSubject(att *SignedAttestation) (string, error) {
462
463
}
463
464
return subject , err
464
465
}
465
-
466
- // verifyEnvAndCert
467
-
468
- // TODO: intotoheader
0 commit comments