-2

I have an encoded x509 certificate and I want to update the CommonName (aka Subject or host name).

Here's the code that I have thus far (simplified):

import (
    "crypto/tls",   
    "crypto/x509"
)

...

// parses a public/private key pair from a pair of PEM encoded data
c, _ := tls.X509KeyPair(certPEMBlock, keyPEMBlock)

// parse into a x509 cert object
cert, _ := x509.ParseCertificate(c.Certificate[0])

// I want to modify the Subject here

// I want to encode it back to PEM encoded data of type []bytes

...

Any idea how to update the subject and encoded it back to PEM encoded data of type []bytes?

jersey bean
  • 3,321
  • 4
  • 28
  • 43
  • 1
    You cannot modify the subject of a certificate and write it back. That would defeat the purpose of the certificate. You can create a new certificate with a new subject, but you'd need the CA to sign it. – Burak Serdar Feb 19 '20 at 04:39
  • ok, in that case I'd like to copy as much of the contents over to a new certificate (everything but the Subject). So I would use x509.Certificate and x509.CreateCertificate to create a new one. Is there a way to copy most of the contents over? Also suppose the cert is self-signed. – jersey bean Feb 19 '20 at 04:46
  • You don't need code for this. Just generate a new self-signed certififctae form the same keypair, or a new CSR and get it signed. You can do all that with standard tools. – user207421 Feb 19 '20 at 04:59
  • @user207421 can you be more specific? Maybe submit an answer with full details? – jersey bean Feb 19 '20 at 05:08
  • I updated the title to possibly better reflect my question – jersey bean Feb 19 '20 at 17:20

1 Answers1

1

You can create a new certificate, with code that looks like the following. You'll need the CA private key for this:

func GenerateCertificate(ca *x509.Certificate, caKey crypto.PrivateKey, req x509.CertificateRequest, durYear, durMonth int, keyUsage x509.KeyUsage, extKeyUsage []x509.ExtKeyUsage, rsaKeySize int) (certificate, key *pem.Block, err error) {

    cert := &x509.Certificate{
        Version:         req.Version,
        SerialNumber:    RandomBigInt(),
        Subject:         req.Subject,
        Extensions:      req.Extensions,
        ExtraExtensions: req.ExtraExtensions,
        DNSNames:        req.DNSNames,
        EmailAddresses:  req.EmailAddresses,
        IPAddresses:     req.IPAddresses,
        URIs:            req.URIs,
        NotBefore:       time.Now(),
        NotAfter:        time.Now().AddDate(durYear, durMonth, 0),
        ExtKeyUsage:     extKeyUsage,
        KeyUsage:        keyUsage,
    }
    priv, _ := rsa.GenerateKey(rand.Reader, rsaKeySize)
    pub := &priv.PublicKey

    var data []byte
    data, err = x509.CreateCertificate(rand.Reader, cert, ca, pub, caKey)
    if err != nil {
        return
    }
    // Public key
    certificate = &pem.Block{Type: "CERTIFICATE", Bytes: data}
    // Private key
    key = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}
    return
}

Use it as:

    subject := pkix.Name{CommonName:"name"}
    cert, certKey, err := GenerateCertificate(caCert, key, x509.CertificateRequest{Subject: subject}, 1, 0, x509.KeyUsageDigitalSignature,
        []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 2048)

You need to find out the key usage, ext key usage, etc. or copy them from the old cert. You can initialize the certificate request passed into GenerateCertificate from the old certificate you have.

If you need a self-signed cert, you can use something like below (I use this to generate a self-signed CA). You have to copy information from the old cert into this one.

func GenerateCA(subject pkix.Name, duryear, durmonth int, rsaKeySize int) (certificate, key *pem.Block, err error) {
    ca := &x509.Certificate{
        SerialNumber:          RandomBigInt(),
        Subject:               subject,
        NotBefore:             time.Now(),
        NotAfter:              time.Now().AddDate(duryear, durmonth, 0),
        IsCA:                  false, // or true?
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
        KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
        BasicConstraintsValid: true,
    }

    priv, _ := rsa.GenerateKey(rand.Reader, rsaKeySize)
    pub := &priv.PublicKey
    var data []byte
    data, err = x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
    if err != nil {
        return
    }

    // Public key
    certificate = &pem.Block{Type: "CERTIFICATE", Bytes: data}
    // Private key
    key = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}
    return
}
Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
  • Thx! This might be what I am looking for. I'll give this approach a try before voting it as an answer. – jersey bean Feb 19 '20 at 05:13
  • This is how you do it with code. You can do it with openssl tools, or with cfssl. Search "how to generate certificates using openssl", there are many tutorials out there. – Burak Serdar Feb 19 '20 at 05:15
  • Yes, I'm looking for a way to do this with Go code. The go docs about CreateCertificate are a bit confusing. Its not clear to me how the template vs parent are being used. From the src code, it appears template should contain all of the filled out fields, whereas parent is only used to determine if it should be self-signed. – jersey bean Feb 19 '20 at 17:24
  • If by parent you mean the CA, then not really. CA signs it, and CA itself can be self-signed. I added code that shows generation of a self-signed CA, which you can modify to generate a self-signed cert with additional info, – Burak Serdar Feb 19 '20 at 17:37