@@ -2,22 +2,104 @@ package enclave
22
33import (
44 "context"
5+ "crypto"
6+ "crypto/ecdsa"
7+ "crypto/elliptic"
58 "crypto/rand"
9+ "crypto/rsa"
10+ "crypto/x509"
11+ "crypto/x509/pkix"
12+ "encoding/asn1"
13+ "encoding/pem"
614 "fmt"
715 "io"
16+ "math"
17+ "math/big"
818 "sync/atomic"
19+ "time"
920
1021 "github.com/0xsequence/nsm/request"
1122 "github.com/0xsequence/nsm/response"
23+ "github.com/fxamacker/cbor/v2"
1224)
1325
14- func DummyProvider (_ context.Context ) (Session , error ) {
15- return & dummySession {random : rand .Reader }, nil
26+ var dummyPrivKey = `-----BEGIN RSA PRIVATE KEY-----
27+ MIIEpAIBAAKCAQEAujDWnWEKVYoHUwieLegkzR2K+4z2Fg3uVEwmZ16iRJiYm5TO
28+ ltLN6BSHaLCqreA1bYXXTFlIG10z2+h16fhkCNKzy4yKwjwUdXJlbBivypQers8h
29+ Pwy1l4c+uID/VX5zXG4y7g7aNc0Ude+lzBvydh9vFz5PwupFzY6ok3czI95ODni7
30+ hn/X/8TBGTyh0eYZu8ehfKy6W9AHbX7D+yL2qebSWWkJBEribptpCcaJi8QPUx9M
31+ HWz8j1j83+M6rnG1FQpLl8VNOO6BXmzb5FNr+6lwEfvwHbht0Azhk0ArMQZ/r0lO
32+ ObAvVDmE2AuudXyWWh5sRrXnXlVitDjTQybQAQIDAQABAoIBAQCYf9Poh0jdkvY4
33+ zkAwvYkW73GcY3JT0gk4xj5WQC6MHKgyFgm3guXfhqD54GmLjK52DD+xaxciQo5t
34+ OdMKVcYpa9qTh4NHX8oqAA6OIRIqzHLtHv3OFGzPtZhrqkx4C+AU/rV8QnH7ywNN
35+ LYIQ0XsfwNNOqFzP+u49VPFCB0m9v7r7mJxeUXp8PDfdhquFT69hpKwNdpzuIDA7
36+ kVOG4ATkkPTGp3AmJj9Vrit9ffi+xlbhrNIuBui9Fxo1v5G6VT2uBhXJU22zl1hS
37+ uYWT4rCOwVQaV/TBDj4T8diDxYpnAXvpO8U+WdqLddhUNaYeDym/HPq2cFsN9VdY
38+ 9FYiVl4ZAoGBAOWVsrRAWgFTmx99nUwy6XhobSWgZDrCQiSK50VGzblBdVnmMvyW
39+ Q3LmdqtVQUkZLETx7PZXYkvIzMRP4oWGcViBPaSZ/IqX/kF5WJeXWW7Zgl5HEXTk
40+ GaN26xl7yFjQ5l0f++HAwSW485B2GXvMcdp+6n7OfG6Xo1cg8CgWck5TAoGBAM+c
41+ /h03pASGVvUDNNfeDulyxcXR/PZZTt1YMTqeYLmkbkJcIJVa2uTdDmzcEbGDA0eq
42+ ezMDA+omGB+WR7HRe9+vgmz7Ww4BZRhKjvnxRgHlTGYHBsHhYr21fgPteGv/aDi2
43+ xhAGqyOj1jua8ooqpw8TviYXk6ZbxMNF7eV9KxXbAoGAasEjKaHKuFcyCICWhfoe
44+ ifi02AwuzwvJSci1JYd43a3MbZMXHlCY6HK1t5GbG+xyo1SDRUD42hhy7s3enQwY
45+ 5HikO0fHIILwnW1ZfpPH6D2H22LcgSgXq+T+CQl/7ZyloaPfsee5aFsKFqBz1RcJ
46+ 0fm1/GTzg1FLiJYuVdWqLTUCgYAaOURHwH1xLN7S9+K22Y+coSimAg4nt8QkZT1i
47+ oBqrmD9tFmHvO5imi92Elo+NknTZmokROnJGIyWs57iKl2FEMdERnvYzYK26UcCZ
48+ hYZIOwRZZs3Ns4BbYg9Ww6oQSiSJ9VwzLgRz7f/ja4DzPsv3NZExEo1N2A2UdMLF
49+ 1/eXPQKBgQDSCJ1tWQYVLvjrzJBC5gute7kHf1AhMoIEqpsEvk51JXu7+xN8BMnb
50+ zSwIPR3fSngqLJqGw+Tz5LT3iSsDNVj7EnaHoYvTrxsd2yFYtVmz2fHgnHXBjZmj
51+ AzDn4G6VZ+F11K/sdfuo+1vfgxPendYDkjp0ZtgJc97iBq49Devv1A==
52+ -----END RSA PRIVATE KEY-----`
53+ var dummyCert = `-----BEGIN CERTIFICATE-----
54+ MIIDITCCAgmgAwIBAgIBATANBgkqhkiG9w0BAQsFADAyMREwDwYDVQQKEwhTZXF1
55+ ZW5jZTEdMBsGA1UEAxMUZHVtbXkubml0cm8tZW5jbGF2ZXMwHhcNMjUwNDI0MTM0
56+ NjA5WhcNMzUwNDI0MTM0NjA5WjAyMREwDwYDVQQKEwhTZXF1ZW5jZTEdMBsGA1UE
57+ AxMUZHVtbXkubml0cm8tZW5jbGF2ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
58+ ggEKAoIBAQC6MNadYQpVigdTCJ4t6CTNHYr7jPYWDe5UTCZnXqJEmJiblM6W0s3o
59+ FIdosKqt4DVthddMWUgbXTPb6HXp+GQI0rPLjIrCPBR1cmVsGK/KlB6uzyE/DLWX
60+ hz64gP9VfnNcbjLuDto1zRR176XMG/J2H28XPk/C6kXNjqiTdzMj3k4OeLuGf9f/
61+ xMEZPKHR5hm7x6F8rLpb0AdtfsP7Ivap5tJZaQkESuJum2kJxomLxA9TH0wdbPyP
62+ WPzf4zqucbUVCkuXxU047oFebNvkU2v7qXAR+/AduG3QDOGTQCsxBn+vSU45sC9U
63+ OYTYC651fJZaHmxGtedeVWK0ONNDJtABAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
64+ hjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSw2hfihIyfiqyiuiuTp3OCt0Sl
65+ 8DANBgkqhkiG9w0BAQsFAAOCAQEAl55+EnYlS5/YTQQhZozA/XW7Y9Kt00w9k0Ix
66+ 9vXTVeZdzTNR/YKCAzG7ynNjNbdFkhJcqqwKycVOSID0Xz4dWvB6jVukIV6B3W2u
67+ ta/P4SYg4VQ9YzPqF1n1sUzX3OwKOhEcSxQQjvs8ssRaWq9aqEHyxCxuc9BWoqvB
68+ Am9iwrNpmUmlRbFwDOwtICZRbqAf799pOFo1i8WKQc/J5y1KwZCCg3GAEBv8CNQE
69+ vMVH5ygi1fMeQPNg8oWDD+3gP1GmLGMP14kHT/aPyDAHHUMrq7nSgA8SXTC9fihO
70+ sygULgtpiSjKgeg9cTvK9yhz7T0c2CxFgyhUnz4v6uZtQTJK2Q==
71+ -----END CERTIFICATE-----`
72+
73+ func DummyProvider () (Session , error ) {
74+ block , _ := pem .Decode ([]byte (dummyPrivKey ))
75+ if block == nil || block .Type != "RSA PRIVATE KEY" {
76+ return nil , fmt .Errorf ("invalid PEM block" )
77+ }
78+ key , err := x509 .ParsePKCS1PrivateKey (block .Bytes )
79+ if err != nil {
80+ return nil , fmt .Errorf ("failed to parse dummy private key: %v" , err )
81+ }
82+
83+ certBlock , _ := pem .Decode ([]byte (dummyCert ))
84+ caCert , err := x509 .ParseCertificate (certBlock .Bytes )
85+ if err != nil {
86+ return nil , fmt .Errorf ("failed to parse CA certificate: %v" , err )
87+ }
88+
89+ return & dummySession {
90+ random : rand .Reader ,
91+ privateKey : key ,
92+ caCert : caCert ,
93+ caCertDER : certBlock .Bytes ,
94+ }, nil
1695}
1796
1897type dummySession struct {
19- random io.Reader
20- closed atomic.Bool
98+ privateKey * rsa.PrivateKey
99+ caCert * x509.Certificate
100+ caCertDER []byte
101+ random io.Reader
102+ closed atomic.Bool
21103}
22104
23105func (d * dummySession ) Read (p []byte ) (n int , err error ) {
@@ -32,7 +114,7 @@ func (d *dummySession) Close() error {
32114 return nil
33115}
34116
35- func (d * dummySession ) Send (req request.Request ) (response.Response , error ) {
117+ func (d * dummySession ) Send (ctx context. Context , req request.Request ) (response.Response , error ) {
36118 switch req := req .(type ) {
37119 case * request.Attestation :
38120 return d .handleAttestation (req )
@@ -44,14 +126,71 @@ func (d *dummySession) Send(req request.Request) (response.Response, error) {
44126}
45127
46128func (d * dummySession ) handleAttestation (req * request.Attestation ) (response.Response , error ) {
47- document := []byte ("DEV ONLY. NOT FOR PROD USE." )
48- if len (req .Nonce ) > 0 {
49- document = append (document , []byte (" NONCE=" )... )
50- document = append (document , req .Nonce ... )
129+ certDER , privateKey , err := d .generateCertificate ()
130+ if err != nil {
131+ return response.Response {}, fmt .Errorf ("failed to generate certificate: %v" , err )
132+ }
133+
134+ pcr := make ([]byte , 48 )
135+ rawDoc := struct {
136+ ModuleID string `cbor:"module_id"`
137+ Timestamp uint64 `cbor:"timestamp"`
138+ Digest string `cbor:"digest"`
139+ PCRs map [int ][]byte `cbor:"pcrs"`
140+ Certificate []byte `cbor:"certificate"`
141+ CABundle [][]byte `cbor:"cabundle"`
142+ PublicKey []byte `cbor:"public_key"`
143+ UserData []byte `cbor:"user_data"`
144+ Nonce []byte `cbor:"nonce"`
145+ }{
146+ ModuleID : "dummy-module" ,
147+ Timestamp : uint64 (time .Now ().Unix () * 1000 ),
148+ Digest : "SHA384" ,
149+ PCRs : map [int ][]byte {
150+ 0 : pcr ,
151+ 1 : pcr ,
152+ 2 : pcr ,
153+ 3 : pcr ,
154+ },
155+ Certificate : certDER ,
156+ CABundle : [][]byte {d .caCertDER },
157+ PublicKey : req .PublicKey ,
158+ UserData : req .UserData ,
159+ Nonce : req .Nonce ,
160+ }
161+
162+ rawDocBytes , err := cbor .Marshal (rawDoc )
163+ if err != nil {
164+ return response.Response {}, fmt .Errorf ("failed to marshal raw document: %v" , err )
165+ }
166+
167+ sigStructCBOR , err := cbor .Marshal ([]any {"Signature1" , []byte {}, []byte {}, rawDocBytes })
168+ if err != nil {
169+ return response.Response {}, fmt .Errorf ("failed to marshal signature structure: %v" , err )
170+ }
171+ hash := crypto .SHA384 .New ()
172+ if _ , err := hash .Write (sigStructCBOR ); err != nil {
173+ return response.Response {}, fmt .Errorf ("failed to hash signature structure: %v" , err )
51174 }
52- if len (req .PublicKey ) > 0 {
53- document = append (document , []byte (" PUBKEY=" )... )
54- document = append (document , req .PublicKey ... )
175+ digest := hash .Sum (nil )
176+
177+ derSig , err := privateKey .Sign (rand .Reader , digest , crypto .SHA384 )
178+ if err != nil {
179+ return response.Response {}, fmt .Errorf ("failed to sign digest: %v" , err )
180+ }
181+
182+ var esig struct { R , S * big.Int }
183+ if _ , err := asn1 .Unmarshal (derSig , & esig ); err != nil {
184+ return response.Response {}, fmt .Errorf ("failed to unmarshal ASN.1 signature: %v" , err )
185+ }
186+
187+ rBytes := esig .R .FillBytes (make ([]byte , 48 )) // 48 bytes for P-384
188+ sBytes := esig .S .FillBytes (make ([]byte , 48 ))
189+ sig := append (rBytes , sBytes ... )
190+
191+ document , err := cbor .Marshal ([]any {[]byte {}, struct {}{}, rawDocBytes , sig })
192+ if err != nil {
193+ return response.Response {}, fmt .Errorf ("failed to marshal COSE_Sign1: %v" , err )
55194 }
56195
57196 res := response.Response {
@@ -72,3 +211,36 @@ func (d *dummySession) handleDescribePCR(req *request.DescribePCR) (response.Res
72211 }
73212 return res , nil
74213}
214+
215+ func (d * dummySession ) generateCertificate () ([]byte , * ecdsa.PrivateKey , error ) {
216+ privateKey , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
217+ if err != nil {
218+ return nil , nil , fmt .Errorf ("failed to generate private key: %v" , err )
219+ }
220+
221+ serialNumber , err := rand .Int (rand .Reader , big .NewInt (math .MaxInt64 ))
222+ if err != nil {
223+ return nil , nil , fmt .Errorf ("failed to generate serial number: %v" , err )
224+ }
225+
226+ template := x509.Certificate {
227+ SerialNumber : serialNumber ,
228+ Subject : pkix.Name {
229+ Organization : []string {"Sequence" },
230+ CommonName : "dummy.nitro-enclaves" ,
231+ },
232+ NotBefore : time .Now (),
233+ NotAfter : time .Now ().Add (time .Hour * 24 ),
234+ KeyUsage : x509 .KeyUsageDigitalSignature | x509 .KeyUsageContentCommitment ,
235+ ExtKeyUsage : []x509.ExtKeyUsage {},
236+ BasicConstraintsValid : true ,
237+ IsCA : false ,
238+ }
239+
240+ certBytes , err := x509 .CreateCertificate (rand .Reader , & template , d .caCert , & privateKey .PublicKey , d .privateKey )
241+ if err != nil {
242+ return nil , nil , fmt .Errorf ("failed to create certificate: %v" , err )
243+ }
244+
245+ return certBytes , privateKey , nil
246+ }
0 commit comments