Created
January 12, 2023 11:02
-
-
Save Tatskaari/5e9ff5c51edcaa7d8a3d63d718349cd3 to your computer and use it in GitHub Desktop.
CA based signing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"crypto/rand" | |
"crypto/x509" | |
"crypto/x509/pkix" | |
"encoding/asn1" | |
"encoding/pem" | |
"log" | |
"os" | |
"github.com/sigstore/sigstore/pkg/signature/kms/gcp" | |
) | |
// PrintCSR creates a signing request for a key stored in google's KMS. We can't do this through openssl like normal, | |
// because we don't have access to the private key, and google haven't implemented anything like this in their SDK or | |
// API. | |
func PrintCSR(key string) error { | |
s, err := gcp.LoadSignerVerifier(context.Background(), key) | |
if err != nil { | |
return err | |
} | |
sig, _, err := s.CryptoSigner(context.Background(), nil) | |
if err != nil { | |
return err | |
} | |
subj := pkix.Name{ | |
CommonName: "release.please.build", | |
Country: []string{"GB"}, | |
Province: []string{"London"}, | |
Locality: []string{"London"}, | |
Organization: []string{"Thought Machine"}, | |
OrganizationalUnit: []string{"Engineering"}, | |
} | |
keyUsage := x509.KeyUsageDigitalSignature | |
extKeyUsage, err := marshalKeyUsage(keyUsage) | |
if err != nil { | |
log.Fatal(err) | |
} | |
template := x509.CertificateRequest{ | |
Subject: subj, | |
DNSNames: []string{"releases.please.build"}, | |
ExtraExtensions: []pkix.Extension{extKeyUsage}, | |
} | |
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, sig) | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
return pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}) | |
} | |
// marshalKeyUsage creates an extension to specify the key usage as digital sig. This code was borrowed from here: | |
// https://stackoverflow.com/questions/69412331/how-to-add-keyusage-to-certificate-signing-request-in-golang | |
func marshalKeyUsage(ku x509.KeyUsage) (pkix.Extension, error) { | |
// As specified somewhere deep in the pki docs | |
keyUsageID := asn1.ObjectIdentifier{2, 5, 29, 15} | |
ext := pkix.Extension{Id: keyUsageID, Critical: true} | |
var a [2]byte | |
a[0] = reverseBitsInAByte(byte(ku)) | |
a[1] = reverseBitsInAByte(byte(ku >> 8)) | |
l := 1 | |
if a[1] != 0 { | |
l = 2 | |
} | |
bitString := a[:l] | |
var err error | |
ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)}) | |
if err != nil { | |
return ext, err | |
} | |
return ext, nil | |
} | |
func reverseBitsInAByte(in byte) byte { | |
b1 := in>>4 | in<<4 | |
b2 := b1>>2&0x33 | b1<<2&0xcc | |
b3 := b2>>1&0x55 | b2<<1&0xaa | |
return b3 | |
} | |
func asn1BitLength(bitString []byte) int { | |
bitLen := len(bitString) * 8 | |
for i := range bitString { | |
b := bitString[len(bitString)-i-1] | |
for bit := uint(0); bit < 8; bit++ { | |
if (b>>bit)&1 == 1 { | |
return bitLen | |
} | |
bitLen-- | |
} | |
} | |
return 0 | |
} | |
// This program generates a certificate sign request from a key stored in GCP's KMS | |
// | |
// Usage: Pass in a key URI like so as the argument to this program: | |
// csr gcpkms://projects/tm-please/locations/eur5/keyRings/please-release/cryptoKeys/please-release-2/cryptoKeyVersions/1 | |
func main() { | |
if err := PrintCSR(os.Args[1]); err != nil { | |
panic(err) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SingAndVerify loads a cert chain .pem and verifies the certificate against an embedded root cert. It then signs a message | |
// with out kms key and verifies the signature with the cert. | |
func SingAndVerify() { | |
f, err := os.Open("please.cer") | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
certs, err := cryptoutils.LoadCertificatesFromPEM(f) | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
roots := x509.NewCertPool() | |
bs, err := os.ReadFile("root.crt") | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
roots.AppendCertsFromPEM(bs) | |
opts := x509.VerifyOptions{ | |
Roots: roots, | |
Intermediates: x509.NewCertPool(), | |
} | |
// Walk through the chain backwards adding the certs as needed. | |
for i := range certs { | |
if i == 0 { | |
continue | |
} | |
cert := certs[len(certs)-i-1] | |
if _, err := cert.Verify(opts); err != nil { | |
panic(err) | |
} | |
opts.Intermediates.AddCert(cert) | |
} | |
// The fist cert is the one we signed with | |
cert := certs[0] | |
_, err = cert.Verify(opts) | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
verifier, err := signature.LoadVerifier(certs[0].PublicKey.(crypto.PublicKey), crypto.SHA256) | |
if err != nil { | |
log.Fatalf("%v", err) | |
} | |
s, err := gcp.LoadSignerVerifier(context.Background(), "gcpkms://projects/tm-please/locations/eur5/keyRings/please-release/cryptoKeys/please-release/cryptoKeyVersions/1") | |
if err != nil { | |
log.Fatalf("err: %v", err) | |
} | |
sig, err := s.SignMessage(strings.NewReader("message")) | |
if err != nil { | |
log.Fatalf("err: %v", err) | |
} | |
err = verifier.VerifySignature(bytes.NewReader(sig), strings.NewReader("message")) | |
if err != nil { | |
log.Fatalf("err: %v", err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment