go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/signing/signingtest/signer.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package signingtest 16 17 import ( 18 "context" 19 "crypto" 20 "crypto/rand" 21 "crypto/rsa" 22 "crypto/sha256" 23 "crypto/x509" 24 "encoding/hex" 25 "encoding/pem" 26 "math/big" 27 "time" 28 29 "go.chromium.org/luci/server/auth/signing" 30 ) 31 32 // Signer holds private key and corresponding cert and can sign blobs with 33 // PKCS1v15. 34 type Signer struct { 35 priv *rsa.PrivateKey 36 certs signing.PublicCertificates 37 serviceInfo signing.ServiceInfo 38 } 39 40 var _ signing.Signer = (*Signer)(nil) 41 42 // NewSigner returns Signer instance that use small random key. 43 // 44 // Panics on errors. 45 func NewSigner(serviceInfo *signing.ServiceInfo) *Signer { 46 priv, err := rsa.GenerateKey(rand.Reader, 512) 47 if err != nil { 48 panic(err) 49 } 50 51 // Generate fake self signed certificate. 52 template := x509.Certificate{ 53 SerialNumber: big.NewInt(1), 54 NotBefore: time.Unix(1000000000, 0), 55 NotAfter: time.Unix(10000000000, 0), 56 KeyUsage: x509.KeyUsageDigitalSignature, 57 BasicConstraintsValid: true, 58 } 59 der, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) 60 if err != nil { 61 panic(err) 62 } 63 64 // PEM-encode it, derive the name. 65 pemOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) 66 keyName := sha256.Sum256(der) 67 68 // Put in default service info if necessary. 69 if serviceInfo == nil { 70 serviceInfo = &signing.ServiceInfo{} 71 } 72 73 return &Signer{ 74 priv: priv, 75 certs: signing.PublicCertificates{ 76 AppID: serviceInfo.AppID, 77 ServiceAccountName: serviceInfo.ServiceAccountName, 78 Certificates: []signing.Certificate{ 79 { 80 KeyName: hex.EncodeToString(keyName[:20]), 81 X509CertificatePEM: string(pemOut), 82 }, 83 }, 84 Timestamp: signing.JSONTime(time.Unix(1000000000, 0)), 85 }, 86 serviceInfo: *serviceInfo, 87 } 88 } 89 90 // SignBytes signs the blob with some active private key. 91 // Returns the signature and name of the key used. 92 func (s *Signer) SignBytes(ctx context.Context, blob []byte) (keyName string, signature []byte, err error) { 93 // Passing nil as 'rand' to SignPKCS1v15 disables RSA blinding, making 94 // the signature deterministic, but reduces overall security. Do not do it 95 // in non testing code. 96 digest := sha256.Sum256(blob) 97 sig, err := rsa.SignPKCS1v15(nil, s.priv, crypto.SHA256, digest[:]) 98 return s.certs.Certificates[0].KeyName, sig, err 99 } 100 101 // Certificates returns a bundle with public certificates for all active keys. 102 func (s *Signer) Certificates(ctx context.Context) (*signing.PublicCertificates, error) { 103 return &s.certs, nil 104 } 105 106 // ServiceInfo returns information about the current service. 107 // 108 // It includes app ID and the service account name (that ultimately owns the 109 // signing private key). 110 func (s *Signer) ServiceInfo(ctx context.Context) (*signing.ServiceInfo, error) { 111 return &s.serviceInfo, nil 112 } 113 114 // KeyForTest returns the RSA key used internally by the test signer. 115 // 116 // It is not part of the signing.Signer interface. It should be used only from 117 // tests. 118 func (s *Signer) KeyForTest() *rsa.PrivateKey { 119 return s.priv 120 } 121 122 // KeyNameForTest returns an ID of the signing key. 123 func (s *Signer) KeyNameForTest() string { 124 return s.certs.Certificates[0].KeyName 125 }