Skip to content

Instantly share code, notes, and snippets.

@joemiller
Last active January 13, 2017 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joemiller/c97a52d46cae0a4b38df841db8307fc4 to your computer and use it in GitHub Desktop.
Save joemiller/c97a52d46cae0a4b38df841db8307fc4 to your computer and use it in GitHub Desktop.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"os"
"time"
"github.com/davecgh/go-spew/spew"
)
func main() {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("failed to generate rsa key: %s", err)
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
log.Fatalf("error generating serial number: %s", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Country: []string{"c1", "c2"},
Locality: []string{"l1", "l2"},
StreetAddress: []string{"addr1", "addr2"},
PostalCode: []string{"post1", "post2"},
Province: []string{"prov1", "prov2"},
Organization: []string{"Acme Co", "second org"},
OrganizationalUnit: []string{"ou1", "ou2"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(3 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
log.Fatalf("Failed to create certificate: %s", err)
}
certOut, err := os.Create("cert.pem")
if err != nil {
log.Fatalf("error opening cert.pem: %s", err)
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
reparsed, err := x509.ParseCertificate(derBytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("re-parsed cert subject: %s\n", spew.Sdump(reparsed.Subject))
}
@joemiller
Copy link
Author

joemiller commented Jan 13, 2017

This demonstrates handling of x509 certs with multiple OU (OrganizationalUnit)s in golang.

Summary:

  • x509.CreateCertificate() is able to create certs whose subject contains multiple OUs
  • x509.ParseCertificate() parses certs containing multiple OUs but will drop all but the first value.

This code will generate a new self-signed certificate with a subject containing two OU's: ou1, ou2 using the x509.CreateCertificate() func. The result of this func is written to a file cert.pem.

Next, it will call x509.ParseCertificate() using the DER-encoded []byte returned from x509.CreateCertificate() and then print the subject line decoded from the cert.

Example:

$ go run foo.go
re-parsed cert subject: (pkix.Name) {
 Country: ([]string) (len=1 cap=1) {
  (string) (len=2) "c1"
 },
 Organization: ([]string) (len=1 cap=1) {
  (string) (len=7) "Acme Co"
 },
 OrganizationalUnit: ([]string) (len=1 cap=1) {
  (string) (len=3) "ou1"
 },
 Locality: ([]string) (len=1 cap=1) {
  (string) (len=2) "l1"
 },
 Province: ([]string) (len=1 cap=1) {
  (string) (len=5) "prov1"
 },
 StreetAddress: ([]string) (len=1 cap=1) {
  (string) (len=5) "addr1"
 },
 PostalCode: ([]string) (len=1 cap=1) {
  (string) (len=5) "post1"
 },
 SerialNumber: (string) "",
 CommonName: (string) "",
 Names: ([]pkix.AttributeTypeAndValue) (len=7 cap=8) {
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.6,
   Value: (string) (len=2) "c1"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.8,
   Value: (string) (len=5) "prov1"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.7,
   Value: (string) (len=2) "l1"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.9,
   Value: (string) (len=5) "addr1"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.17,
   Value: (string) (len=5) "post1"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.10,
   Value: (string) (len=7) "Acme Co"
  },
  (pkix.AttributeTypeAndValue) {
   Type: (asn1.ObjectIdentifier) (len=4 cap=4) 2.5.4.11,
   Value: (string) (len=3) "ou1"
  }
 },
 ExtraNames: ([]pkix.AttributeTypeAndValue) <nil>
}

The parsed certificates subject contains only the first specified values.

Next, parse the cert.pem using OpenSSL and see that it contains multiple values for each of the expected attributes.

$ openssl x509 -subject -noout -in cert.pem
subject= /C=c1/C=c2/ST=prov1/ST=prov2/L=l1/L=l2/street=addr1/street=addr2/postalCode=post1/postalCode=post2/O=Acme Co/O=second org/OU=ou1/OU=ou2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment