goopensslcryptographycsrou

Create a CSR with OU separated by comma instead of plus character


I am trying to create a certificate signing request in go using the crypto lib. The problem is it generates the CSR with OU separated by +, i.e.

Subject: O = Example Org, OU = OU1 + OU = OU2, CN = example.com

How can I generate the CSR with OU separated by , like

Subject: O = Example Org, OU = OU1, OU = OU2, CN = example.com

Producing OU separated by + seems to be default behaviour of crypto lib. Can this be done using crypto lib? If no, then is there any other lib that can generate CSR with OU separated by ,

I tried generating the CSR using below code

package main

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

func main() {
    privKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrTemplate := x509.CertificateRequest{
        Subject: pkix.Name{
            CommonName:         "example.com",
            Organization:       []string{"Example Org"},
            OrganizationalUnit: []string{"OU1", "OU2"},
        },
        EmailAddresses: []string{"test@example.com"},
    }

    csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, privKey)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrPem := pem.EncodeToMemory(&pem.Block{
        Type:  "CERTIFICATE REQUEST",
        Bytes: csrBytes,
    })

    fmt.Println(string(csrPem))
}


Solution

  • Neither the '+' nor the ',' are part of the certificate. It is just what is used when providing a human readable string representation of the certificate request.

    In detail: your code just prints out a CSR file in PEM format, not a human readable presentation of the certificate request. Looking at this CSR with asn1parse gives:

    $ openssl asn1parse -in csr.pem 
       ...       
       37:d=4  hl=2 l=  10 cons: SEQUENCE          
       39:d=5  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
       44:d=5  hl=2 l=   3 prim: PRINTABLESTRING   :OU1
       49:d=4  hl=2 l=  10 cons: SEQUENCE          
       51:d=5  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
       56:d=5  hl=2 l=   3 prim: PRINTABLESTRING   :OU2
       61:d=3  hl=2 l=  20 cons: SET    
    

    So, these are separate objects and not a combined string with a '+' between. This '+' instead comes when displaying the certificate request using req:

    $ openssl req -in csr.pem -text 
    Certificate Request:
        Data:
            Version: 1 (0x0)
            Subject: O = Example Org, OU = OU1 + OU = OU2, CN = example.com
    

    Which separator is used here can actually be kind of configured. See openssl-namedisplay-options and look for sep_comma_plus_space, which is the default separator. To cite the documentation:

    The first word is used between the Relative Distinguished Names (RDNs) and the second is between multiple Attribute Value Assertions (AVAs). Multiple AVAs are very rare and their use is discouraged.

    So there you have it: a comma is used between different RDN (i.e. O, OU, CN, ...) while a plus is used between multiple AVA inside the same RDN (like multiple OU). Also, using multiple AVA is discouraged anyway.