Skip to content

Commit fc4b55e

Browse files
authored
Merge pull request oasisprotocol#2168 from oasisprotocol/kostko/feature/orc-sgx-setsig-rngkey
2 parents f44fc72 + e1bf113 commit fc4b55e

File tree

1 file changed

+133
-30
lines changed

1 file changed

+133
-30
lines changed

tools/orc/main.go

Lines changed: 133 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package main
22

33
import (
4+
"crypto/rand"
45
"crypto/rsa"
56
"crypto/x509"
67
"encoding/pem"
78
"fmt"
9+
"io"
10+
"math/big"
811
"os"
912
"strings"
1013

@@ -121,51 +124,73 @@ var (
121124
}
122125

123126
sgxSetSigCmd = &cobra.Command{
124-
Use: "sgx-set-sig [--component ID] <bundle.orc> <signature.sig> <public_key.pub>",
127+
Use: "sgx-set-sig [--component ID] <bundle.orc> [<signature.sig> <public_key.pub>]",
125128
Short: "add or overwrite an SGXS signature to an existing runtime bundle",
126-
Args: cobra.ExactArgs(3),
129+
Args: cobra.RangeArgs(1, 3),
127130
Run: func(cmd *cobra.Command, args []string) {
128-
bundlePath, sigPath, publicKey := args[0], args[1], args[2]
131+
var sigPath, publicKey string
132+
bundlePath := args[0]
133+
switch len(args) {
134+
case 1:
135+
case 3:
136+
sigPath, publicKey = args[1], args[2]
137+
default:
138+
cobra.CheckErr("unsupported number of arguments")
139+
}
129140
compId := getComponentID()
130141

131142
rawCompId, _ := compId.MarshalText()
132143
sgxSigName := fmt.Sprintf(sgxSigNameFmt, string(rawCompId))
133144

134-
// Load public key.
135-
rawPub, err := os.ReadFile(publicKey)
136-
if err != nil {
137-
cobra.CheckErr(fmt.Errorf("failed to read public key: %w", err))
138-
}
139-
pubPem, _ := pem.Decode(rawPub)
140-
if pubPem == nil {
141-
cobra.CheckErr(fmt.Errorf("failed to decode public key pem file"))
142-
}
143-
pub, err := x509.ParsePKIXPublicKey(pubPem.Bytes)
144-
if err != nil {
145-
cobra.CheckErr(fmt.Errorf("failed to parse public key: %w", err))
146-
}
147-
pubKey, ok := pub.(*rsa.PublicKey)
148-
if !ok {
149-
cobra.CheckErr(fmt.Errorf("invalid public key type: %T", pub))
150-
}
151-
152145
// Load bundle.
153146
bnd, err := bundle.Open(bundlePath)
154147
if err != nil {
155148
cobra.CheckErr(fmt.Errorf("failed to open bundle: %w", err))
156149
}
157150

158-
// Load signature file.
159-
rawSig, err := os.ReadFile(sigPath)
160-
if err != nil {
161-
cobra.CheckErr(fmt.Errorf("failed to load signature file: %w", err))
162-
}
163-
164151
// Construct sigstruct from provided arguments.
152+
var signed []byte
165153
sigstruct := constructSigstruct(bnd, compId)
166-
signed, err := sigstruct.WithSignature(rawSig, pubKey)
167-
if err != nil {
168-
cobra.CheckErr(fmt.Errorf("failed to append signature: %w", err))
154+
switch sigPath {
155+
case "":
156+
// Generate a new random key and sign the sigstruct.
157+
sigKey, err := sgxGenerateKey(rand.Reader)
158+
if err != nil {
159+
cobra.CheckErr(fmt.Errorf("failed to generate signer key: %w", err))
160+
}
161+
signed, err = sigstruct.Sign(sigKey)
162+
if err != nil {
163+
cobra.CheckErr(fmt.Errorf("failed to sign SIGSTRUCT: %w", err))
164+
}
165+
default:
166+
// Load public key.
167+
rawPub, err := os.ReadFile(publicKey)
168+
if err != nil {
169+
cobra.CheckErr(fmt.Errorf("failed to read public key: %w", err))
170+
}
171+
pubPem, _ := pem.Decode(rawPub)
172+
if pubPem == nil {
173+
cobra.CheckErr(fmt.Errorf("failed to decode public key pem file"))
174+
}
175+
pub, err := x509.ParsePKIXPublicKey(pubPem.Bytes)
176+
if err != nil {
177+
cobra.CheckErr(fmt.Errorf("failed to parse public key: %w", err))
178+
}
179+
pubKey, ok := pub.(*rsa.PublicKey)
180+
if !ok {
181+
cobra.CheckErr(fmt.Errorf("invalid public key type: %T", pub))
182+
}
183+
184+
// Load signature file.
185+
rawSig, err := os.ReadFile(sigPath)
186+
if err != nil {
187+
cobra.CheckErr(fmt.Errorf("failed to load signature file: %w", err))
188+
}
189+
190+
signed, err = sigstruct.WithSignature(rawSig, pubKey)
191+
if err != nil {
192+
cobra.CheckErr(fmt.Errorf("failed to append signature: %w", err))
193+
}
169194
}
170195
err = bnd.Add(sgxSigName, bundle.NewBytesData(signed))
171196
cobra.CheckErr(err)
@@ -531,6 +556,84 @@ func showTdxComponent(indent string, bnd *bundle.Bundle, comp *bundle.Component)
531556
fmt.Printf("%s Memory: %d MiB\n", indent, comp.TDX.Resources.Memory)
532557
}
533558

559+
// sgxGenerateKey generates a 3072-bit RSA key with public exponent 3 as required for SGX.
560+
//
561+
// The code below is adopted from the Go standard library as it is otherwise not possible to
562+
// customize the exponent.
563+
func sgxGenerateKey(random io.Reader) (*rsa.PrivateKey, error) {
564+
priv := new(rsa.PrivateKey)
565+
priv.E = 3
566+
bits := 3072
567+
nprimes := 2
568+
569+
bigOne := big.NewInt(1)
570+
primes := make([]*big.Int, nprimes)
571+
572+
NextSetOfPrimes:
573+
for {
574+
todo := bits
575+
// crypto/rand should set the top two bits in each prime.
576+
// Thus each prime has the form
577+
// p_i = 2^bitlen(p_i) × 0.11... (in base 2).
578+
// And the product is:
579+
// P = 2^todo × α
580+
// where α is the product of nprimes numbers of the form 0.11...
581+
//
582+
// If α < 1/2 (which can happen for nprimes > 2), we need to
583+
// shift todo to compensate for lost bits: the mean value of 0.11...
584+
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
585+
// will give good results.
586+
if nprimes >= 7 {
587+
todo += (nprimes - 2) / 5
588+
}
589+
for i := 0; i < nprimes; i++ {
590+
var err error
591+
primes[i], err = rand.Prime(random, todo/(nprimes-i))
592+
if err != nil {
593+
return nil, err
594+
}
595+
todo -= primes[i].BitLen()
596+
}
597+
598+
// Make sure that primes is pairwise unequal.
599+
for i, prime := range primes {
600+
for j := 0; j < i; j++ {
601+
if prime.Cmp(primes[j]) == 0 {
602+
continue NextSetOfPrimes
603+
}
604+
}
605+
}
606+
607+
n := new(big.Int).Set(bigOne)
608+
totient := new(big.Int).Set(bigOne)
609+
pminus1 := new(big.Int)
610+
for _, prime := range primes {
611+
n.Mul(n, prime)
612+
pminus1.Sub(prime, bigOne)
613+
totient.Mul(totient, pminus1)
614+
}
615+
if n.BitLen() != bits {
616+
// This should never happen for nprimes == 2 because
617+
// crypto/rand should set the top two bits in each prime.
618+
// For nprimes > 2 we hope it does not happen often.
619+
continue NextSetOfPrimes
620+
}
621+
622+
priv.D = new(big.Int)
623+
e := big.NewInt(int64(priv.E))
624+
ok := priv.D.ModInverse(e, totient)
625+
626+
if ok != nil {
627+
priv.Primes = primes
628+
priv.N = n
629+
break
630+
}
631+
}
632+
633+
priv.Precompute()
634+
return priv, nil
635+
}
636+
534637
func main() {
535638
_ = rootCmd.Execute()
536639
}

0 commit comments

Comments
 (0)