Initial import.

This commit is contained in:
Kyle Isom 2015-06-10 16:29:52 -07:00
commit 7391da8567
12 changed files with 365 additions and 0 deletions

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright (c) 2015 Kyle Isom <kyle@tyrfingr.is>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

22
README.md Normal file
View File

@ -0,0 +1,22 @@
GOUTILS
This is a collection of small utility code I've written in Go; the `cmd/`
directory has a number of command-line utilities. Rather than keep all
of these in superfluous repositories of their own, I'm putting them here.
Contents:
die/ Death of a program.
cmd/
certchain/ Display the certificate chain from a
TLS connection.
csrpubdump/ Dump the public key from an X.509
certificate request.
readchain/ Print the common name for the certificates
in a bundle.
stealchain/ Dump the verified chain from a TLS
connection.
Each program should have a small README in the directory with more information.
All code here is licensed under the MIT license.

19
cmd/certchain/README Normal file
View File

@ -0,0 +1,19 @@
certchain
This is a utility for printing the X.509 certificate chain from a TLS
connection.
Note: while this will accept more than one server, it will print all
of the chains without any indication where one chain ends and the next
begins. This was the intended behaviour for the use case, but it may
not be applicable in other cases.
There are no knobs.
Examples:
$ certchain www.kyleisom.net
-----BEGIN CERTIFICATE-----
MIIFUTCCBDmgAwIBAgIQaaTVw0yZFGAYvFDKAIo4BzANBgkqhkiG9w0BAQsFADCB
kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV
...

View File

@ -0,0 +1,39 @@
package main
import (
"crypto/tls"
"encoding/pem"
"flag"
"fmt"
"regexp"
"github.com/kisom/goutils/die"
)
var hasPort = regexp.MustCompile(`:\d+$`)
func main() {
flag.Parse()
for _, server := range flag.Args() {
if !hasPort.MatchString(server) {
server += ":443"
}
var chain string
conn, err := tls.Dial("tcp", server, nil)
die.If(err)
details := conn.ConnectionState()
for _, cert := range details.PeerCertificates {
p := pem.Block{
Type: "CERTIFICATE",
Bytes: cert.Raw,
}
chain += string(pem.EncodeToMemory(&p))
}
fmt.Println(chain)
}
}

18
cmd/csrpubdump/README Normal file
View File

@ -0,0 +1,18 @@
csrpubdump
This is a small utility to dump the public key from an X.509 certificate
signature request (CSR) to a standard RFC 5280 PKIX public key format.
There are no command line flags; it accepts a number of PEM- or
DER-enoded CSRs and outputs a public key of the same name as the CSR
with the suffix ".pub" appended.
Example:
$ csrpubdump cert.csr
[+] wrote cert.csr.pub.
$ openssl req -text -in cert.csr -modulus | grep ^Modulus
Modulus=C7021819792D3ADE906156868B6475B67E475325A1AAD6C50BFD8CFE007A4B7C50E89CCA91EF14EEB13AD4B01E8FABDF6884AA74B9CAFFF4D4FD8C26ECAA9DD9DC4D232C3A54FFEE7EBB4CCD34BB4D4AFFD73FB2880A10A8E5CA99533FBC85746FDC3AEFFDA8A6FF25A95DDB010B15813AC6AD910C5CB1CA264E07783B67B1716B977A69D7C647067336D50BE3FF2CF8BCA2A9DC3D2357E441DEB4E29A1914DD30AD0B3895F8564D47E0D2B1EE879C2018A3F75736696EDF056F5BCD8DF6C7B688711B63C253A272F837356D27D4CD67109DE9E9F39F16E05F33EE9179C9B767151DF5DC78E8B2A5E71B6F33213ACE69D3131DA27ACCE86011A7D43965CECE33687C50456B622E0804FE213458D6D0BF82AA711B01FFCAE54DD7D046F14A67D3E1C089EDA62821DF48100A4FF5DEE2E98F79AC526C8A96B16F1C93E7776F8A2BF5166FE5C651713DE88A426DF92406EBDA56E0E01B6FE001B2CFCD22EAE2EB3D1EEC311E20BE739B2489A9DB581DD35837BFBEBFDC4136C2F822C53A204CB7F9
$ openssl rsa -pubin -text -in cert.csr.pub -modulus | grep ^Modulus
Modulus=C7021819792D3ADE906156868B6475B67E475325A1AAD6C50BFD8CFE007A4B7C50E89CCA91EF14EEB13AD4B01E8FABDF6884AA74B9CAFFF4D4FD8C26ECAA9DD9DC4D232C3A54FFEE7EBB4CCD34BB4D4AFFD73FB2880A10A8E5CA99533FBC85746FDC3AEFFDA8A6FF25A95DDB010B15813AC6AD910C5CB1CA264E07783B67B1716B977A69D7C647067336D50BE3FF2CF8BCA2A9DC3D2357E441DEB4E29A1914DD30AD0B3895F8564D47E0D2B1EE879C2018A3F75736696EDF056F5BCD8DF6C7B688711B63C253A272F837356D27D4CD67109DE9E9F39F16E05F33EE9179C9B767151DF5DC78E8B2A5E71B6F33213ACE69D3131DA27ACCE86011A7D43965CECE33687C50456B622E0804FE213458D6D0BF82AA711B01FFCAE54DD7D046F14A67D3E1C089EDA62821DF48100A4FF5DEE2E98F79AC526C8A96B16F1C93E7776F8A2BF5166FE5C651713DE88A426DF92406EBDA56E0E01B6FE001B2CFCD22EAE2EB3D1EEC311E20BE739B2489A9DB581DD35837BFBEBFDC4136C2F822C53A204CB7F9

55
cmd/csrpubdump/pubdump.go Normal file
View File

@ -0,0 +1,55 @@
package main
import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"log"
"github.com/kisom/die"
)
func main() {
flag.Parse()
for _, fileName := range flag.Args() {
in, err := ioutil.ReadFile(fileName)
die.If(err)
if p, _ := pem.Decode(in); p != nil {
if p.Type != "CERTIFICATE REQUEST" {
log.Fatal("INVALID FILE TYPE")
}
in = p.Bytes
}
csr, err := x509.ParseCertificateRequest(in)
die.If(err)
out, err := x509.MarshalPKIXPublicKey(csr.PublicKey)
die.If(err)
var t string
switch pub := csr.PublicKey.(type) {
case *rsa.PublicKey:
t = "RSA PUBLIC KEY"
case *ecdsa.PublicKey:
t = "EC PUBLIC KEY"
default:
die.With("unrecognised public key type %T", pub)
}
p := &pem.Block{
Type: t,
Bytes: out,
}
err = ioutil.WriteFile(fileName+".pub", pem.EncodeToMemory(p), 0644)
die.If(err)
fmt.Printf("[+] wrote %s.\n", fileName+".pub")
}
}

20
cmd/readchain/README Normal file
View File

@ -0,0 +1,20 @@
readchain
This is a small utility to read a chain of PEM-encoded X.509 certificates
and print their common names. It was written to quickly see what certificates
were in a bundle.
It is called with the files containing chains to read passed in as an
argument. The program has no knobs or widgets to adjust.
Examples:
$ readchain google.com.pem microsoft.com.pem
[+] google.com.pem:
*.google.com
Google Internet Authority G2
GeoTrust Global CA
[+] microsoft.com.pem:
microsoft.com
MSIT Machine Auth CA 2
Microsoft Internet Authority

40
cmd/readchain/chain.go Normal file
View File

@ -0,0 +1,40 @@
package main
import (
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"os"
)
func main() {
flag.Parse()
for _, fileName := range flag.Args() {
data, err := ioutil.ReadFile(fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "[!] %s: %v\n", fileName, err)
continue
}
fmt.Printf("[+] %s:\n", fileName)
rest := data[:]
for {
var p *pem.Block
p, rest = pem.Decode(rest)
if p == nil {
break
}
cert, err := x509.ParseCertificate(p.Bytes)
if err != nil {
fmt.Fprintf(os.Stderr, "[!] %s: %v\n", fileName, err)
break
}
fmt.Printf("\t%+v\n", cert.Subject.CommonName)
}
}
}

42
cmd/stealchain/README Normal file
View File

@ -0,0 +1,42 @@
stealchain
This is a utility to extract the verified X.509 chain from a TLS
connection. It takes a list of sites on the command line; for each
site that it can connect to, it will dump the certificates that the
peer actually sent (and not the verified chain that is built from
this).
It was written to assist in debugging issues with certificate chains.
There are a few knobs:
-ca allows the trusted CA roots to be specified via a PEM bundle of
root certificates.
-sni specifies the server name for SNI. This applies to all hosts in
the run; if this is run as
$ stealchain -sni foo.com foo.com bar.com
it will attempt to use "foo.com" as the server name for both hosts.
-noverify skips certificate verification. This might be useful for seeing
what certificates a server is actually sending.
Examples:
$ stealchain kyleisom.net
[+] wrote kyleisom.net.pem.
$ readchain kyleisom.net.pem
[+] kyleisom.net.pem:
*.kyleisom.net
COMODO RSA Domain Validation Secure Server CA
$ stealchain google.com microsoft.com apple.com amazon.com
[+] wrote google.com.pem.
[+] wrote microsoft.com.pem.
[+] wrote apple.com.pem.
[+] wrote amazon.com.pem.

63
cmd/stealchain/thief.go Normal file
View File

@ -0,0 +1,63 @@
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/kisom/goutils/die"
)
func main() {
var cfg = &tls.Config{}
var sysRoot, serverName string
flag.StringVar(&sysRoot, "ca", "", "provide an alternate CA bundle")
flag.StringVar(&cfg.ServerName, "sni", cfg.ServerName, "provide an SNI name")
flag.BoolVar(&cfg.InsecureSkipVerify, "noverify", false, "don't verify certificates")
flag.Parse()
if sysRoot != "" {
pemList, err := ioutil.ReadFile(sysRoot)
die.If(err)
roots := x509.NewCertPool()
if !roots.AppendCertsFromPEM(pemList) {
fmt.Printf("[!] no valid roots found")
roots = nil
}
cfg.RootCAs = roots
}
if serverName != "" {
cfg.ServerName = serverName
}
for _, site := range flag.Args() {
conn, err := tls.Dial("tcp", site+":443", cfg)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
cs := conn.ConnectionState()
var chain []byte
for _, cert := range cs.PeerCertificates {
p := &pem.Block{
Type: "CERTIFICATE",
Bytes: cert.Raw,
}
chain = append(chain, pem.EncodeToMemory(p)...)
}
err = ioutil.WriteFile(site+".pem", chain, 0644)
die.If(err)
fmt.Printf("[+] wrote %s.pem.\n", site)
}
}

12
die/README.md Normal file
View File

@ -0,0 +1,12 @@
Simple fatal utilities for Go programs.
```
result, err := doSomething()
die.If(err)
ok := processResult(result)
if !ok {
die.With("failed to process result %s", result.Name)
}
```

22
die/die.go Normal file
View File

@ -0,0 +1,22 @@
// Package die contains utilities for fatal error handling.
package die
import (
"fmt"
"os"
)
// If prints the error to stderr and exits if err != nil.
func If(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "[!] %v\n", err)
os.Exit(1)
}
}
// With prints the message to stderr, appending a newline, and exits.
func With(fstr string, args ...interface{}) {
out := fmt.Sprintf("[!] %s\n", fstr)
fmt.Fprintf(os.Stderr, out, args...)
os.Exit(1)
}