Skip to content

Instantly share code, notes, and snippets.

Last active Dec 3, 2015
What would you like to do?
Go program to add name constraints to a certificate
* Adds name constraints to a certificate. Useful if you need to
* import your organization's private CA into your web browser, but
* you only want to trust it for your organization's domains and not
* the Internet at large.
* The certificate is re-signed by an ephemeral issuer with a random
* key so you don't need access to the private key. A random serial number
* is placed in the Issuer DN so browsers don't attempt to verify the
* signature when you import the certificate.
* Note that name-constrained roots only work in some web browsers.
* So far, the certificates produced by this program have been tested
* successfully in:
* - Firefox 38 ESR on Linux
* A PEM-encoded certificate is read from stdin and the new PEM-encoded
* certificate is written to stdout. The domain names to which the
* certificate should be constrained are specified as command line arguments.
* Example:
* name_constrain < example-root.crt > example-root-constrained.crt
* Written in 2015 by Andrew Ayer <>
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
* You should have received a copy of the CC0 Public
* Domain Dedication along with this software. If not, see
* <>.
package main
import (
var maxSerialNumber = new(big.Int).Lsh(big.NewInt(1), 128)
func randomSerialNumber() string {
n, err := rand.Int(rand.Reader, maxSerialNumber)
if err != nil {
panic("Random number generator failed: " + err.Error())
return n.String()
func main() {
crtPem, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fmt.Fprintln(os.Stderr, "Error reading from stdin:", err)
pemBlock, _ := pem.Decode(crtPem)
if pemBlock == nil {
fmt.Fprintln(os.Stderr, "Invalid PEM read from stdin")
crts, err := x509.ParseCertificates(pemBlock.Bytes)
if err != nil {
fmt.Fprintln(os.Stderr, "Error parsing certificate:", err)
crts[0].PermittedDNSDomainsCritical = true
crts[0].PermittedDNSDomains = os.Args[1:]
parent := &x509.Certificate{Subject: crts[0].Issuer}
parent.Subject.OrganizationalUnit = append(parent.Subject.OrganizationalUnit, "Dummy issuer added by name_constrain.go")
parent.Subject.SerialNumber = randomSerialNumber()
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("Error generating RSA key:", err)
newCrtDer, err := x509.CreateCertificate(rand.Reader, crts[0], parent, crts[0].PublicKey, key)
if err != nil {
fmt.Println("Error creating certificate:", err)
err = pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: newCrtDer})
if err != nil {
fmt.Println("Error writing certificate to stdout:", err)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment