Last active
December 3, 2015 04:28
-
-
Save AGWA/c343e4be85399d65a81b to your computer and use it in GitHub Desktop.
Go program to add name constraints to a certificate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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.com example.org < example-root.crt > example-root-constrained.crt | |
* | |
* Written in 2015 by Andrew Ayer <[email protected]> | |
* | |
* 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 | |
* <http://creativecommons.org/publicdomain/zero/1.0/>. | |
*/ | |
package main | |
import ( | |
"crypto/rand" | |
"crypto/rsa" | |
"crypto/x509" | |
"encoding/pem" | |
"fmt" | |
"io/ioutil" | |
"math/big" | |
"os" | |
) | |
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) | |
os.Exit(1) | |
} | |
pemBlock, _ := pem.Decode(crtPem) | |
if pemBlock == nil { | |
fmt.Fprintln(os.Stderr, "Invalid PEM read from stdin") | |
os.Exit(1) | |
} | |
crts, err := x509.ParseCertificates(pemBlock.Bytes) | |
if err != nil { | |
fmt.Fprintln(os.Stderr, "Error parsing certificate:", err) | |
os.Exit(1) | |
} | |
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) | |
os.Exit(1) | |
} | |
newCrtDer, err := x509.CreateCertificate(rand.Reader, crts[0], parent, crts[0].PublicKey, key) | |
if err != nil { | |
fmt.Println("Error creating certificate:", err) | |
os.Exit(1) | |
} | |
err = pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: newCrtDer}) | |
if err != nil { | |
fmt.Println("Error writing certificate to stdout:", err) | |
os.Exit(1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment