0

I'm trying to create a CSR using Golang. I've seen multiple implementations using the crypto/x509 library. I've found that the most reasonable one is this implementation, which I found in this question:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "crypto/x509/pkix"
    "encoding/asn1"
    "encoding/pem"
    "fmt"
    "os"
)

var oidEmailAddress = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}

func main() {
    keyBytes, _ := rsa.GenerateKey(rand.Reader, 1024)

    emailAddress := "test@example.com"
    subj := pkix.Name{
        CommonName:         "example.com",
        Country:            []string{"AU"},
        Province:           []string{"Some-State"},
        Locality:           []string{"MyCity"},
        Organization:       []string{"Company Ltd"},
        OrganizationalUnit: []string{"IT"},
        ExtraNames: []pkix.AttributeTypeAndValue{
            {
                Type: oidEmailAddress,
                Value: asn1.RawValue{
                    Tag:   asn1.TagIA5String,
                    Bytes: []byte(emailAddress),
                },
            },
        },
    }

    template := x509.CertificateRequest{
        Subject:            subj,
        SignatureAlgorithm: x509.SHA256WithRSA,
    }

    csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, &template, keyBytes)
    pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes})

}

Now, my problem is that I don't have access to the private key. It's stored remotely in a safe location, via an API call I have the ability to retrieve the PEM encoded public key as well as sign the Certification Request Info with the private key.

Can you please let me know if you're aware of a way I can create the Certificate Request using a "dummy" private key and then be able to edit the ASN.1 formatted results with the proper public key and new signature? Or even better, create the CSR without a "dummy" private key at all?

I've tried to edit the x509 Certificate Request object, but if I edit the attributes of Signature and PublicKey, the value of the Raw ASN.1 does not change accordingly.

csr, _ := x509.ParseCertificateRequest(csrBytes)
csrRawOld := csr.Raw
fmt.Printf("CSR Public Key is: %v\n", csr.PublicKey)
csr.PublicKey = []byte{1, 2, 3, 4}
fmt.Printf("CSR Public Key is now: %v\n", csr.PublicKey)
fmt.Printf("CSR Signature is: %v\n", csr.Signature)
csr.Signature = []byte{1, 2, 3, 4}
fmt.Printf("CSR Signature is now: %v\n", csr.Signature)
if reflect.DeepEqual(csrRawOld, csr.Raw) {
    fmt.Printf("Raw ASN.1 is the same")
}

In the end, they remain the same. I would appreciate help if you know how to change the ASN.1 value.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 2
    The signature must be computed using the private key corresponding to the public key included in the CSR. This is how you prove you have access to the key. This is not optional. – Marc Sep 01 '22 at 12:30
  • That is more than clear to me... I just cannot have the private key bytes in memory. Therefore, I want to be able to add the Public Key manually and then sign the info using the API available to me. I could do this in python using the asn1crypto package. – Eatay Mizrachi Sep 01 '22 at 12:31

0 Answers0