Initial import.
This commit is contained in:
commit
7391da8567
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||||
|
...
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in New Issue