diff options
20 files changed, 1900 insertions, 394 deletions
@@ -4,6 +4,6 @@ github.com/jacobsa/oglematchers 3ecefc49db07722beca986d9bb71ddd026b133f0 github.com/smartystreets/goconvey 995f5b2e021c69b8b028ba6d0b05c1dd500783db github.com/jessevdk/go-flags 5e118789801496c93ba210d34ef1f2ce5a9173bd github.com/3rf/mongo-lint f6cf4f8a7d07167375b035d186a1e8b3ebf28aa3 -github.com/spacemonkeygo/openssl 4c6dbafa5ec35b3ffc6a1b1e1fe29c3eba2053ec github.com/10gen/openssl +github.com/spacemonkeygo/openssl 28e108cf76dcb7bd5aa445a0f4348b312464004e github.com/10gen/openssl github.com/howeyc/gopass 2c70fa70727c953c51695f800f25d6b44abb368e golang.org/x/crypto c57d4a71915a248dbad846d60825145062b4c18e diff --git a/vendor/src/github.com/spacemonkeygo/openssl/build.go b/vendor/src/github.com/spacemonkeygo/openssl/build.go index e24a0c8db63..dd72651d3ea 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/build.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/build.go @@ -18,5 +18,6 @@ package openssl // #cgo linux pkg-config: openssl // #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN +// #cgo darwin CFLAGS: -Wno-deprecated-declarations // #cgo darwin LDFLAGS: -lssl -lcrypto import "C" diff --git a/vendor/src/github.com/spacemonkeygo/openssl/cert.go b/vendor/src/github.com/spacemonkeygo/openssl/cert.go new file mode 100644 index 00000000000..61637c649fa --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/cert.go @@ -0,0 +1,407 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cgo + +package openssl + +// #include <openssl/conf.h> +// #include <openssl/ssl.h> +// #include <openssl/x509v3.h> +// +// void OPENSSL_free_not_a_macro(void *ref) { OPENSSL_free(ref); } +// +import "C" + +import ( + "errors" + "io/ioutil" + "math/big" + "runtime" + "time" + "unsafe" +) + +type EVP_MD int + +const ( + EVP_NULL EVP_MD = iota + EVP_MD5 EVP_MD = iota + EVP_SHA EVP_MD = iota + EVP_SHA1 EVP_MD = iota + EVP_DSS EVP_MD = iota + EVP_DSS1 EVP_MD = iota + EVP_MDC2 EVP_MD = iota + EVP_RIPEMD160 EVP_MD = iota + EVP_SHA224 EVP_MD = iota + EVP_SHA256 EVP_MD = iota + EVP_SHA384 EVP_MD = iota + EVP_SHA512 EVP_MD = iota +) + +type Certificate struct { + x *C.X509 + Issuer *Certificate + ref interface{} + pubKey PublicKey +} + +type CertificateInfo struct { + Serial *big.Int + Issued time.Duration + Expires time.Duration + Country string + Organization string + CommonName string +} + +type Name struct { + name *C.X509_NAME +} + +// Allocate and return a new Name object. +func NewName() (*Name, error) { + n := C.X509_NAME_new() + if n == nil { + return nil, errors.New("could not create x509 name") + } + name := &Name{name: n} + runtime.SetFinalizer(name, func(n *Name) { + C.X509_NAME_free(n.name) + }) + return name, nil +} + +// AddTextEntry appends a text entry to an X509 NAME. +func (n *Name) AddTextEntry(field, value string) error { + cfield := C.CString(field) + defer C.free(unsafe.Pointer(cfield)) + cvalue := (*C.uchar)(unsafe.Pointer(C.CString(value))) + defer C.free(unsafe.Pointer(cvalue)) + ret := C.X509_NAME_add_entry_by_txt( + n.name, cfield, C.MBSTRING_ASC, cvalue, -1, -1, 0) + if ret != 1 { + return errors.New("failed to add x509 name text entry") + } + return nil +} + +// AddTextEntries allows adding multiple entries to a name in one call. +func (n *Name) AddTextEntries(entries map[string]string) error { + for f, v := range entries { + if err := n.AddTextEntry(f, v); err != nil { + return err + } + } + return nil +} + +// GetEntry returns a name entry based on NID. If no entry, then ("", false) is +// returned. +func (n *Name) GetEntry(nid NID) (entry string, ok bool) { + entrylen := C.X509_NAME_get_text_by_NID(n.name, C.int(nid), nil, 0) + if entrylen == -1 { + return "", false + } + buf := (*C.char)(C.malloc(C.size_t(entrylen + 1))) + defer C.free(unsafe.Pointer(buf)) + C.X509_NAME_get_text_by_NID(n.name, C.int(nid), buf, entrylen+1) + return C.GoStringN(buf, entrylen), true +} + +// NewCertificate generates a basic certificate based +// on the provided CertificateInfo struct +func NewCertificate(info *CertificateInfo, key PublicKey) (*Certificate, error) { + c := &Certificate{x: C.X509_new()} + runtime.SetFinalizer(c, func(c *Certificate) { + C.X509_free(c.x) + }) + + name, err := c.GetSubjectName() + if err != nil { + return nil, err + } + err = name.AddTextEntries(map[string]string{ + "C": info.Country, + "O": info.Organization, + "CN": info.CommonName, + }) + if err != nil { + return nil, err + } + // self-issue for now + if err := c.SetIssuerName(name); err != nil { + return nil, err + } + if err := c.SetSerial(info.Serial); err != nil { + return nil, err + } + if err := c.SetIssueDate(info.Issued); err != nil { + return nil, err + } + if err := c.SetExpireDate(info.Expires); err != nil { + return nil, err + } + if err := c.SetPubKey(key); err != nil { + return nil, err + } + return c, nil +} + +func (c *Certificate) GetSubjectName() (*Name, error) { + n := C.X509_get_subject_name(c.x) + if n == nil { + return nil, errors.New("failed to get subject name") + } + return &Name{name: n}, nil +} + +func (c *Certificate) GetIssuerName() (*Name, error) { + n := C.X509_get_issuer_name(c.x) + if n == nil { + return nil, errors.New("failed to get issuer name") + } + return &Name{name: n}, nil +} + +func (c *Certificate) SetSubjectName(name *Name) error { + if C.X509_set_subject_name(c.x, name.name) != 1 { + return errors.New("failed to set subject name") + } + return nil +} + +// SetIssuer updates the stored Issuer cert +// and the internal x509 Issuer Name of a certificate. +// The stored Issuer reference is used when adding extensions. +func (c *Certificate) SetIssuer(issuer *Certificate) error { + name, err := issuer.GetSubjectName() + if err != nil { + return err + } + if err = c.SetIssuerName(name); err != nil { + return err + } + c.Issuer = issuer + return nil +} + +// SetIssuerName populates the issuer name of a certificate. +// Use SetIssuer instead, if possible. +func (c *Certificate) SetIssuerName(name *Name) error { + if C.X509_set_issuer_name(c.x, name.name) != 1 { + return errors.New("failed to set subject name") + } + return nil +} + +// SetSerial sets the serial of a certificate. +func (c *Certificate) SetSerial(serial *big.Int) error { + sno := C.ASN1_INTEGER_new() + defer C.ASN1_INTEGER_free(sno) + bn := C.BN_new() + defer C.BN_free(bn) + + serialBytes := serial.Bytes() + if bn = C.BN_bin2bn((*C.uchar)(unsafe.Pointer(&serialBytes[0])), C.int(len(serialBytes)), bn); bn == nil { + return errors.New("failed to set serial") + } + if sno = C.BN_to_ASN1_INTEGER(bn, sno); sno == nil { + return errors.New("failed to set serial") + } + if C.X509_set_serialNumber(c.x, sno) != 1 { + return errors.New("failed to set serial") + } + return nil +} + +// SetIssueDate sets the certificate issue date relative to the current time. +func (c *Certificate) SetIssueDate(when time.Duration) error { + offset := C.long(when / time.Second) + result := C.X509_gmtime_adj(c.x.cert_info.validity.notBefore, offset) + if result == nil { + return errors.New("failed to set issue date") + } + return nil +} + +// SetExpireDate sets the certificate issue date relative to the current time. +func (c *Certificate) SetExpireDate(when time.Duration) error { + offset := C.long(when / time.Second) + result := C.X509_gmtime_adj(c.x.cert_info.validity.notAfter, offset) + if result == nil { + return errors.New("failed to set expire date") + } + return nil +} + +// SetPubKey assigns a new public key to a certificate. +func (c *Certificate) SetPubKey(pubKey PublicKey) error { + c.pubKey = pubKey + if C.X509_set_pubkey(c.x, pubKey.evpPKey()) != 1 { + return errors.New("failed to set public key") + } + return nil +} + +// Sign a certificate using a private key and a digest name. +// Accepted digest names are 'sha256', 'sha384', and 'sha512'. +func (c *Certificate) Sign(privKey PrivateKey, digest EVP_MD) error { + switch digest { + case EVP_SHA256: + case EVP_SHA384: + case EVP_SHA512: + default: + return errors.New("Unsupported digest" + + "You're probably looking for 'EVP_SHA256' or 'EVP_SHA512'.") + } + return c.insecureSign(privKey, digest) +} + +func (c *Certificate) insecureSign(privKey PrivateKey, digest EVP_MD) error { + var md *C.EVP_MD + switch digest { + // please don't use these digest functions + case EVP_NULL: + md = C.EVP_md_null() + case EVP_MD5: + md = C.EVP_md5() + case EVP_SHA: + md = C.EVP_sha() + case EVP_SHA1: + md = C.EVP_sha1() + case EVP_DSS: + md = C.EVP_dss() + case EVP_DSS1: + md = C.EVP_dss1() + case EVP_RIPEMD160: + md = C.EVP_ripemd160() + case EVP_SHA224: + md = C.EVP_sha224() + // you actually want one of these + case EVP_SHA256: + md = C.EVP_sha256() + case EVP_SHA384: + md = C.EVP_sha384() + case EVP_SHA512: + md = C.EVP_sha512() + } + if C.X509_sign(c.x, privKey.evpPKey(), md) <= 0 { + return errors.New("failed to sign certificate") + } + return nil +} + +// Add an extension to a certificate. +// Extension constants are NID_* as found in openssl. +func (c *Certificate) AddExtension(nid NID, value string) error { + issuer := c + if c.Issuer != nil { + issuer = c.Issuer + } + var ctx C.X509V3_CTX + C.X509V3_set_ctx(&ctx, c.x, issuer.x, nil, nil, 0) + ex := C.X509V3_EXT_conf_nid(nil, &ctx, C.int(nid), C.CString(value)) + if ex == nil { + return errors.New("failed to create x509v3 extension") + } + defer C.X509_EXTENSION_free(ex) + if C.X509_add_ext(c.x, ex, -1) <= 0 { + return errors.New("failed to add x509v3 extension") + } + return nil +} + +// Wraps AddExtension using a map of NID to text extension. +// Will return without finishing if it encounters an error. +func (c *Certificate) AddExtensions(extensions map[NID]string) error { + for nid, value := range extensions { + if err := c.AddExtension(nid, value); err != nil { + return err + } + } + return nil +} + +// LoadCertificateFromPEM loads an X509 certificate from a PEM-encoded block. +func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + cert := C.PEM_read_bio_X509(bio, nil, nil, nil) + C.BIO_free(bio) + if cert == nil { + return nil, errorFromErrorQueue() + } + x := &Certificate{x: cert} + runtime.SetFinalizer(x, func(x *Certificate) { + C.X509_free(x.x) + }) + return x, nil +} + +// MarshalPEM converts the X509 certificate to PEM-encoded format +func (c *Certificate) MarshalPEM() (pem_block []byte, err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + if int(C.PEM_write_bio_X509(bio, c.x)) != 1 { + return nil, errors.New("failed dumping certificate") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +// PublicKey returns the public key embedded in the X509 certificate. +func (c *Certificate) PublicKey() (PublicKey, error) { + pkey := C.X509_get_pubkey(c.x) + if pkey == nil { + return nil, errors.New("no public key found") + } + key := &pKey{key: pkey} + runtime.SetFinalizer(key, func(key *pKey) { + C.EVP_PKEY_free(key.key) + }) + return key, nil +} + +// GetSerialNumberHex returns the certificate's serial number in hex format +func (c *Certificate) GetSerialNumberHex() (serial string) { + asn1_i := C.X509_get_serialNumber(c.x) + bignum := C.ASN1_INTEGER_to_BN(asn1_i, nil) + hex := C.BN_bn2hex(bignum) + serial = C.GoString(hex) + C.BN_free(bignum) + C.OPENSSL_free_not_a_macro(unsafe.Pointer(hex)) + return +} + +func (c *Certificate) X509NamePrintEx() (out []byte, err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + name := C.X509_get_subject_name(c.x) + // TODO, pass in flags instead of using this hardcoded one + if int(C.X509_NAME_print_ex(bio, name, 0, C.XN_FLAG_RFC2253)) < 0 { + return nil, errors.New("failed formatting subject") + } + return ioutil.ReadAll(asAnyBio(bio)) +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go b/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go new file mode 100644 index 00000000000..c32883ba4eb --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go @@ -0,0 +1,139 @@ +// Copyright (C) 2014 Ryan Hileman +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "math/big" + "testing" + "time" +) + +func TestCertGenerate(t *testing.T) { + key, err := GenerateRSAKey(2048) + if err != nil { + t.Fatal(err) + } + info := &CertificateInfo{ + Serial: big.NewInt(int64(1)), + Issued: 0, + Expires: 24 * time.Hour, + Country: "US", + Organization: "Test", + CommonName: "localhost", + } + cert, err := NewCertificate(info, key) + if err != nil { + t.Fatal(err) + } + if err := cert.Sign(key, EVP_SHA256); err != nil { + t.Fatal(err) + } +} + +func TestCAGenerate(t *testing.T) { + cakey, err := GenerateRSAKey(2048) + if err != nil { + t.Fatal(err) + } + info := &CertificateInfo{ + Serial: big.NewInt(int64(1)), + Issued: 0, + Expires: 24 * time.Hour, + Country: "US", + Organization: "Test CA", + CommonName: "CA", + } + ca, err := NewCertificate(info, cakey) + if err != nil { + t.Fatal(err) + } + if err := ca.AddExtensions(map[NID]string{ + NID_basic_constraints: "critical,CA:TRUE", + NID_key_usage: "critical,keyCertSign,cRLSign", + NID_subject_key_identifier: "hash", + NID_netscape_cert_type: "sslCA", + }); err != nil { + t.Fatal(err) + } + if err := ca.Sign(cakey, EVP_SHA256); err != nil { + t.Fatal(err) + } + key, err := GenerateRSAKey(2048) + if err != nil { + t.Fatal(err) + } + info = &CertificateInfo{ + Serial: big.NewInt(int64(1)), + Issued: 0, + Expires: 24 * time.Hour, + Country: "US", + Organization: "Test", + CommonName: "localhost", + } + cert, err := NewCertificate(info, key) + if err != nil { + t.Fatal(err) + } + if err := cert.AddExtensions(map[NID]string{ + NID_basic_constraints: "critical,CA:FALSE", + NID_key_usage: "keyEncipherment", + NID_ext_key_usage: "serverAuth", + }); err != nil { + t.Fatal(err) + } + if err := cert.SetIssuer(ca); err != nil { + t.Fatal(err) + } + if err := cert.Sign(cakey, EVP_SHA256); err != nil { + t.Fatal(err) + } +} + +func TestCertGetNameEntry(t *testing.T) { + key, err := GenerateRSAKey(2048) + if err != nil { + t.Fatal(err) + } + info := &CertificateInfo{ + Serial: big.NewInt(int64(1)), + Issued: 0, + Expires: 24 * time.Hour, + Country: "US", + Organization: "Test", + CommonName: "localhost", + } + cert, err := NewCertificate(info, key) + if err != nil { + t.Fatal(err) + } + name, err := cert.GetSubjectName() + if err != nil { + t.Fatal(err) + } + entry, ok := name.GetEntry(NID_commonName) + if !ok { + t.Fatal("no common name") + } + if entry != "localhost" { + t.Fatalf("expected localhost; got %q", entry) + } + entry, ok = name.GetEntry(NID_localityName) + if ok { + t.Fatal("did not expect a locality name") + } + if entry != "" { + t.Fatalf("entry should be empty; got %q", entry) + } +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go b/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go index 46ea4ced708..12662707f54 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go @@ -73,8 +73,8 @@ type Cipher struct { ptr *C.EVP_CIPHER } -func (c *Cipher) Nid() int { - return int(C.EVP_CIPHER_nid_not_a_macro(c.ptr)) +func (c *Cipher) Nid() NID { + return NID(C.EVP_CIPHER_nid_not_a_macro(c.ptr)) } func (c *Cipher) ShortName() (string, error) { @@ -93,7 +93,7 @@ func (c *Cipher) IVSize() int { return int(C.EVP_CIPHER_iv_length_not_a_macro(c.ptr)) } -func Nid2ShortName(nid int) (string, error) { +func Nid2ShortName(nid NID) (string, error) { sn := C.OBJ_nid2sn(C.int(nid)) if sn == nil { return "", fmt.Errorf("NID %d not found", nid) @@ -112,7 +112,7 @@ func GetCipherByName(name string) (*Cipher, error) { return &Cipher{ptr: p}, nil } -func GetCipherByNid(nid int) (*Cipher, error) { +func GetCipherByNid(nid NID) (*Cipher, error) { sn, err := Nid2ShortName(nid) if err != nil { return nil, err @@ -153,7 +153,13 @@ func (ctx *cipherCtx) applyKeyAndIV(key, iv []byte) error { iptr = (*C.uchar)(&iv[0]) } if kptr != nil || iptr != nil { - if 1 != C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) { + var res C.int + if ctx.ctx.encrypt != 0 { + res = C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } else { + res = C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } + if 1 != res { return errors.New("failed to apply key/IV") } } diff --git a/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go b/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go index b0707dff1e9..d1d430b1e15 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go @@ -251,3 +251,57 @@ func TestBadAAD(t *testing.T) { } checkEqual(t, plaintext_out, plaintext) } + +func TestNonAuthenticatedEncryption(t *testing.T) { + key := []byte("never gonna give you up, never g") + iv := []byte("onna let you dow") + plaintext1 := "n, never gonna run around" + plaintext2 := " and desert you" + + cipher, err := GetCipherByName("aes-256-cbc") + if err != nil { + t.Fatal("Could not get cipher: ", err) + } + + eCtx, err := NewEncryptionCipherCtx(cipher, nil, key, iv) + if err != nil { + t.Fatal("Could not create encryption context: ", err) + } + cipherbytes, err := eCtx.EncryptUpdate([]byte(plaintext1)) + if err != nil { + t.Fatal("EncryptUpdate(plaintext1) failure: ", err) + } + ciphertext := string(cipherbytes) + cipherbytes, err = eCtx.EncryptUpdate([]byte(plaintext2)) + if err != nil { + t.Fatal("EncryptUpdate(plaintext2) failure: ", err) + } + ciphertext += string(cipherbytes) + cipherbytes, err = eCtx.EncryptFinal() + if err != nil { + t.Fatal("EncryptFinal() failure: ", err) + } + ciphertext += string(cipherbytes) + + dCtx, err := NewDecryptionCipherCtx(cipher, nil, key, iv) + if err != nil { + t.Fatal("Could not create decryption context: ", err) + } + plainbytes, err := dCtx.DecryptUpdate([]byte(ciphertext[:15])) + if err != nil { + t.Fatal("DecryptUpdate(ciphertext part 1) failure: ", err) + } + plainOutput := string(plainbytes) + plainbytes, err = dCtx.DecryptUpdate([]byte(ciphertext[15:])) + if err != nil { + t.Fatal("DecryptUpdate(ciphertext part 2) failure: ", err) + } + plainOutput += string(plainbytes) + plainbytes, err = dCtx.DecryptFinal() + if err != nil { + t.Fatal("DecryptFinal() failure: ", err) + } + plainOutput += string(plainbytes) + + checkEqual(t, []byte(plainOutput), plaintext1+plaintext2) +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/conn.go b/vendor/src/github.com/spacemonkeygo/openssl/conn.go index 4049a021801..afc73a50ae3 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/conn.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/conn.go @@ -16,19 +16,28 @@ package openssl -// #include <stdlib.h> -// #include <openssl/ssl.h> -// #include <openssl/conf.h> -// #include <openssl/err.h> -// -// int sk_X509_num_not_a_macro(STACK_OF(X509) *sk) { return sk_X509_num(sk); } -// X509 *sk_X509_value_not_a_macro(STACK_OF(X509)* sk, int i) { -// return sk_X509_value(sk, i); -// } +/* +#include <stdlib.h> +#include <openssl/ssl.h> +#include <openssl/conf.h> +#include <openssl/err.h> + +int sk_X509_num_not_a_macro(STACK_OF(X509) *sk) { return sk_X509_num(sk); } +X509 *sk_X509_value_not_a_macro(STACK_OF(X509)* sk, int i) { + return sk_X509_value(sk, i); +} +const char * SSL_get_cipher_name_not_a_macro(const SSL *ssl) { + return SSL_get_cipher_name(ssl); +} +static int SSL_session_reused_not_a_macro(SSL *ssl) { + return SSL_session_reused(ssl); +} +*/ import "C" import ( "errors" + "fmt" "io" "net" "runtime" @@ -57,6 +66,56 @@ type Conn struct { want_read_future *utils.Future } +type VerifyResult int + +const ( + Ok VerifyResult = C.X509_V_OK + UnableToGetIssuerCert VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + UnableToGetCrl VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_CRL + UnableToDecryptCertSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE + UnableToDecryptCrlSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE + UnableToDecodeIssuerPublicKey VerifyResult = C.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + CertSignatureFailure VerifyResult = C.X509_V_ERR_CERT_SIGNATURE_FAILURE + CrlSignatureFailure VerifyResult = C.X509_V_ERR_CRL_SIGNATURE_FAILURE + CertNotYetValid VerifyResult = C.X509_V_ERR_CERT_NOT_YET_VALID + CertHasExpired VerifyResult = C.X509_V_ERR_CERT_HAS_EXPIRED + CrlNotYetValid VerifyResult = C.X509_V_ERR_CRL_NOT_YET_VALID + CrlHasExpired VerifyResult = C.X509_V_ERR_CRL_HAS_EXPIRED + ErrorInCertNotBeforeField VerifyResult = C.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD + ErrorInCertNotAfterField VerifyResult = C.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD + ErrorInCrlLastUpdateField VerifyResult = C.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD + ErrorInCrlNextUpdateField VerifyResult = C.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD + OutOfMem VerifyResult = C.X509_V_ERR_OUT_OF_MEM + DepthZeroSelfSignedCert VerifyResult = C.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT + SelfSignedCertInChain VerifyResult = C.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN + UnableToGetIssuerCertLocally VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + UnableToVerifyLeafSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE + CertChainTooLong VerifyResult = C.X509_V_ERR_CERT_CHAIN_TOO_LONG + CertRevoked VerifyResult = C.X509_V_ERR_CERT_REVOKED + InvalidCa VerifyResult = C.X509_V_ERR_INVALID_CA + PathLengthExceeded VerifyResult = C.X509_V_ERR_PATH_LENGTH_EXCEEDED + InvalidPurpose VerifyResult = C.X509_V_ERR_INVALID_PURPOSE + CertUntrusted VerifyResult = C.X509_V_ERR_CERT_UNTRUSTED + CertRejected VerifyResult = C.X509_V_ERR_CERT_REJECTED + SubjectIssuerMismatch VerifyResult = C.X509_V_ERR_SUBJECT_ISSUER_MISMATCH + AkidSkidMismatch VerifyResult = C.X509_V_ERR_AKID_SKID_MISMATCH + AkidIssuerSerialMismatch VerifyResult = C.X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH + KeyusageNoCertsign VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_CERTSIGN + UnableToGetCrlIssuer VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER + UnhandledCriticalExtension VerifyResult = C.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION + KeyusageNoCrlSign VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN + UnhandledCriticalCrlExtension VerifyResult = C.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION + InvalidNonCa VerifyResult = C.X509_V_ERR_INVALID_NON_CA + ProxyPathLengthExceeded VerifyResult = C.X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED + KeyusageNoDigitalSignature VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE + ProxyCertificatesNotAllowed VerifyResult = C.X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED + InvalidExtension VerifyResult = C.X509_V_ERR_INVALID_EXTENSION + InvalidPolicyExtension VerifyResult = C.X509_V_ERR_INVALID_POLICY_EXTENSION + NoExplicitPolicy VerifyResult = C.X509_V_ERR_NO_EXPLICIT_POLICY + UnnestedResource VerifyResult = C.X509_V_ERR_UNNESTED_RESOURCE + ApplicationVerification VerifyResult = C.X509_V_ERR_APPLICATION_VERIFICATION +) + func newSSL(ctx *C.SSL_CTX) (*C.SSL, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -141,6 +200,15 @@ func Server(conn net.Conn, ctx *Ctx) (*Conn, error) { return c, nil } +func (c *Conn) CurrentCipher() (string, error) { + p := C.SSL_get_cipher_name_not_a_macro(c.ssl) + if p == nil { + return "", errors.New("Session not established") + } + + return C.GoString(p), nil +} + func (c *Conn) fillInputBuffer() error { for { n, err := c.into_ssl.ReadFromOnce(c.conn) @@ -316,11 +384,13 @@ type ConnectionState struct { CertificateError error CertificateChain []*Certificate CertificateChainError error + SessionReused bool } func (c *Conn) ConnectionState() (rv ConnectionState) { rv.Certificate, rv.CertificateError = c.PeerCertificate() rv.CertificateChain, rv.CertificateChainError = c.PeerCertificateChain() + rv.SessionReused = c.SessionReused() return } @@ -500,3 +570,56 @@ func (c *Conn) UnderlyingConn() net.Conn { return c.conn } +func (c *Conn) VerifyResult() VerifyResult { + return VerifyResult(C.SSL_get_verify_result(c.ssl)) +} + +func (c *Conn) SessionReused() bool { + return C.SSL_session_reused_not_a_macro(c.ssl) == 1 +} + +func (c *Conn) GetSession() ([]byte, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // get1 increases the refcount of the session, so we have to free it. + session := (*C.SSL_SESSION)(C.SSL_get1_session(c.ssl)) + if session == nil { + return nil, errors.New("failed to get session") + } + defer C.SSL_SESSION_free(session) + + // get the size of the encoding + slen := C.i2d_SSL_SESSION(session, nil) + + buf := (*C.uchar)(C.malloc(C.size_t(slen))) + defer C.free(unsafe.Pointer(buf)) + + // this modifies the value of buf (seriously), so we have to pass in a temp + // var so that we can actually read the bytes from buf. + tmp := buf + slen2 := C.i2d_SSL_SESSION(session, &tmp) + if slen != slen2 { + return nil, errors.New("session had different lengths") + } + + return C.GoBytes(unsafe.Pointer(buf), slen), nil +} + +func (c *Conn) setSession(session []byte) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ptr := (*C.uchar)(&session[0]) + s := C.d2i_SSL_SESSION(nil, &ptr, C.long(len(session))) + if s == nil { + return fmt.Errorf("unable to load session: %s", errorFromErrorQueue()) + } + defer C.SSL_SESSION_free(s) + + ret := C.SSL_set_session(c.ssl, s) + if ret != 1 { + return fmt.Errorf("unable to set session: %s", errorFromErrorQueue()) + } + return nil +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/ctx.go b/vendor/src/github.com/spacemonkeygo/openssl/ctx.go index 22d6dd16149..e8c1824f808 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/ctx.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/ctx.go @@ -27,6 +27,14 @@ static long SSL_CTX_set_options_not_a_macro(SSL_CTX* ctx, long options) { return SSL_CTX_set_options(ctx, options); } +static long SSL_CTX_clear_options_not_a_macro(SSL_CTX* ctx, long options) { + return SSL_CTX_clear_options(ctx, options); +} + +static long SSL_CTX_get_options_not_a_macro(SSL_CTX* ctx) { + return SSL_CTX_get_options(ctx); +} + static long SSL_CTX_set_mode_not_a_macro(SSL_CTX* ctx, long modes) { return SSL_CTX_set_mode(ctx, modes); } @@ -39,6 +47,22 @@ static long SSL_CTX_set_session_cache_mode_not_a_macro(SSL_CTX* ctx, long modes) return SSL_CTX_set_session_cache_mode(ctx, modes); } +static long SSL_CTX_sess_set_cache_size_not_a_macro(SSL_CTX* ctx, long t) { + return SSL_CTX_sess_set_cache_size(ctx, t); +} + +static long SSL_CTX_sess_get_cache_size_not_a_macro(SSL_CTX* ctx) { + return SSL_CTX_sess_get_cache_size(ctx); +} + +static long SSL_CTX_set_timeout_not_a_macro(SSL_CTX* ctx, long t) { + return SSL_CTX_set_timeout(ctx, t); +} + +static long SSL_CTX_get_timeout_not_a_macro(SSL_CTX* ctx) { + return SSL_CTX_get_timeout(ctx); +} + static int CRYPTO_add_not_a_macro(int *pointer,int amount,int type) { return CRYPTO_add(pointer, amount, type); } @@ -56,7 +80,7 @@ static long SSL_CTX_add_extra_chain_cert_not_a_macro(SSL_CTX* ctx, X509 *cert) { #endif static const SSL_METHOD *OUR_TLSv1_1_method() { -#ifdef TLS1_1_VERSION +#if OPENSSL_VERSION_NUMBER > 0x1000100fL && defined(TLS1_1_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) return TLSv1_1_method(); #else return NULL; @@ -64,13 +88,17 @@ static const SSL_METHOD *OUR_TLSv1_1_method() { } static const SSL_METHOD *OUR_TLSv1_2_method() { -#ifdef TLS1_2_VERSION +#if OPENSSL_VERSION_NUMBER > 0x1000100fL && defined(TLS1_2_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) return TLSv1_2_method(); #else return NULL; #endif } +#if defined SSL_CTRL_SET_TLSEXT_HOSTNAME + extern int sni_cb(SSL *ssl_conn, int *ad, void *arg); +#endif + extern int verify_cb(int ok, X509_STORE_CTX* store); typedef STACK_OF(X509_NAME) *STACK_OF_X509_NAME_not_a_macro; @@ -89,6 +117,7 @@ import ( "io/ioutil" "os" "runtime" + "time" "unsafe" "github.com/spacemonkeygo/spacelog" @@ -102,7 +131,11 @@ var ( type Ctx struct { ctx *C.SSL_CTX + cert *Certificate + chain []*Certificate + key PrivateKey verify_cb VerifyCallback + sni_cb TLSExtServernameCallback } //export get_ssl_ctx_idx @@ -128,10 +161,13 @@ func newCtx(method *C.SSL_METHOD) (*Ctx, error) { type SSLVersion int const ( - SSLv3 SSLVersion = 0x02 - TLSv1 SSLVersion = 0x03 - TLSv1_1 SSLVersion = 0x04 - TLSv1_2 SSLVersion = 0x05 + SSLv3 SSLVersion = 0x02 // Vulnerable to "POODLE" attack. + TLSv1 SSLVersion = 0x03 + TLSv1_1 SSLVersion = 0x04 + TLSv1_2 SSLVersion = 0x05 + + // Make sure to disable SSLv2 and SSLv3 if you use this. SSLv3 is vulnerable + // to the "POODLE" attack, and SSLv2 is what, just don't even. AnyVersion SSLVersion = 0x06 ) @@ -179,7 +215,12 @@ func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) { return nil, err } - cert, err := LoadCertificateFromPEM(cert_bytes) + certs := SplitPEM(cert_bytes) + if len(certs) == 0 { + return nil, fmt.Errorf("No PEM certificate found in '%s'", cert_file) + } + first, certs := certs[0], certs[1:] + cert, err := LoadCertificateFromPEM(first) if err != nil { return nil, err } @@ -189,6 +230,17 @@ func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) { return nil, err } + for _, pem := range certs { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return nil, err + } + err = ctx.AddChainCertificate(cert) + if err != nil { + return nil, err + } + } + key_bytes, err := ioutil.ReadFile(key_file) if err != nil { return nil, err @@ -223,6 +275,7 @@ const ( func (c *Ctx) UseCertificate(cert *Certificate) error { runtime.LockOSThread() defer runtime.UnlockOSThread() + c.cert = cert if int(C.SSL_CTX_use_certificate(c.ctx, cert.x)) != 1 { return errorFromErrorQueue() } @@ -345,9 +398,12 @@ func (c *Ctx) SetClientCAList(caList *StackOfX509Name) { func (c *Ctx) AddChainCertificate(cert *Certificate) error { runtime.LockOSThread() defer runtime.UnlockOSThread() + c.chain = append(c.chain, cert) if int(C.SSL_CTX_add_extra_chain_cert_not_a_macro(c.ctx, cert.x)) != 1 { return errorFromErrorQueue() } + // OpenSSL takes ownership via SSL_CTX_add_extra_chain_cert + runtime.SetFinalizer(cert, nil) return nil } @@ -356,6 +412,7 @@ func (c *Ctx) AddChainCertificate(cert *Certificate) error { func (c *Ctx) UsePrivateKey(key PrivateKey) error { runtime.LockOSThread() defer runtime.UnlockOSThread() + c.key = key if int(C.SSL_CTX_use_PrivateKey(c.ctx, key.evpPKey())) != 1 { return errorFromErrorQueue() } @@ -364,7 +421,38 @@ func (c *Ctx) UsePrivateKey(key PrivateKey) error { type CertificateStore struct { store *C.X509_STORE - ctx *Ctx // for gc + // for GC + ctx *Ctx + certs []*Certificate +} + +// Allocate a new, empty CertificateStore +func NewCertificateStore() (*CertificateStore, error) { + s := C.X509_STORE_new() + if s == nil { + return nil, errors.New("failed to allocate X509_STORE") + } + store := &CertificateStore{store: s} + runtime.SetFinalizer(store, func(s *CertificateStore) { + C.X509_STORE_free(s.store) + }) + return store, nil +} + +// Parse a chained PEM file, loading all certificates into the Store. +func (s *CertificateStore) LoadCertificatesFromPEM(data []byte) error { + pems := SplitPEM(data) + for _, pem := range pems { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return err + } + err = s.AddCertificate(cert) + if err != nil { + return err + } + } + return nil } // GetCertificateStore returns the context's certificate store that will be @@ -382,6 +470,7 @@ func (c *Ctx) GetCertificateStore() *CertificateStore { func (s *CertificateStore) AddCertificate(cert *Certificate) error { runtime.LockOSThread() defer runtime.UnlockOSThread() + s.certs = append(s.certs, cert) if int(C.X509_STORE_add_cert(s.store, cert.x)) != 1 { return errorFromErrorQueue() } @@ -480,6 +569,10 @@ type CertificateStoreCtx struct { ssl_ctx *Ctx } +func (self *CertificateStoreCtx) VerifyResult() VerifyResult { + return VerifyResult(C.X509_STORE_CTX_get_error(self.ctx)) +} + func (self *CertificateStoreCtx) Err() error { code := C.X509_STORE_CTX_get_error(self.ctx) if code == C.X509_V_OK { @@ -553,6 +646,17 @@ func (c *Ctx) SetOptions(options Options) Options { c.ctx, C.long(options))) } +func (c *Ctx) ClearOptions(options Options) Options { + return Options(C.SSL_CTX_clear_options_not_a_macro( + c.ctx, C.long(options))) +} + +// GetOptions returns context options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (c *Ctx) GetOptions() Options { + return Options(C.SSL_CTX_get_options_not_a_macro(c.ctx)) +} + type Modes int const ( @@ -631,6 +735,10 @@ func (c *Ctx) SetVerifyCallback(verify_cb VerifyCallback) { c.SetVerify(c.VerifyMode(), verify_cb) } +func (c *Ctx) GetVerifyCallback() VerifyCallback { + return c.verify_cb +} + func (c *Ctx) VerifyMode() VerifyOptions { return VerifyOptions(C.SSL_CTX_get_verify_mode(c.ctx)) } @@ -642,6 +750,15 @@ func (c *Ctx) SetVerifyDepth(depth int) { C.SSL_CTX_set_verify_depth(c.ctx, C.int(depth)) } +// GetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (c *Ctx) GetVerifyDepth() int { + return int(C.SSL_CTX_get_verify_depth(c.ctx)) +} + +type TLSExtServernameCallback func(ssl *SSL) SSLTLSExtErr + func (c *Ctx) SetSessionId(session_id []byte) error { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -689,3 +806,28 @@ func (c *Ctx) SetSessionCacheMode(modes SessionCacheModes) SessionCacheModes { return SessionCacheModes( C.SSL_CTX_set_session_cache_mode_not_a_macro(c.ctx, C.long(modes))) } + +// Set session cache timeout. Returns previously set value. +// See https://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html +func (c *Ctx) SetTimeout(t time.Duration) time.Duration { + prev := C.SSL_CTX_set_timeout_not_a_macro(c.ctx, C.long(t/time.Second)) + return time.Duration(prev) * time.Second +} + +// Get session cache timeout. +// See https://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html +func (c *Ctx) GetTimeout() time.Duration { + return time.Duration(C.SSL_CTX_get_timeout_not_a_macro(c.ctx)) * time.Second +} + +// Set session cache size. Returns previously set value. +// https://www.openssl.org/docs/ssl/SSL_CTX_sess_set_cache_size.html +func (c *Ctx) SessSetCacheSize(t int) int { + return int(C.SSL_CTX_sess_set_cache_size_not_a_macro(c.ctx, C.long(t))) +} + +// Get session cache size. +// https://www.openssl.org/docs/ssl/SSL_CTX_sess_set_cache_size.html +func (c *Ctx) SessGetCacheSize() int { + return int(C.SSL_CTX_sess_get_cache_size_not_a_macro(c.ctx)) +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go b/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go new file mode 100644 index 00000000000..9644e518bf3 --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go @@ -0,0 +1,48 @@ +// Copyright (C) 2014 Ryan Hileman +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "testing" + "time" +) + +func TestCtxTimeoutOption(t *testing.T) { + ctx, _ := NewCtx() + oldTimeout1 := ctx.GetTimeout() + newTimeout1 := oldTimeout1 + (time.Duration(99) * time.Second) + oldTimeout2 := ctx.SetTimeout(newTimeout1) + newTimeout2 := ctx.GetTimeout() + if oldTimeout1 != oldTimeout2 { + t.Error("SetTimeout() returns something undocumented") + } + if newTimeout1 != newTimeout2 { + t.Error("SetTimeout() does not save anything to ctx") + } +} + +func TestCtxSessCacheSizeOption(t *testing.T) { + ctx, _ := NewCtx() + oldSize1 := ctx.SessGetCacheSize() + newSize1 := oldSize1 + 42 + oldSize2 := ctx.SessSetCacheSize(newSize1) + newSize2 := ctx.SessGetCacheSize() + if oldSize1 != oldSize2 { + t.Error("SessSetCacheSize() returns something undocumented") + } + if newSize1 != newSize2 { + t.Error("SessSetCacheSize() does not save anything to ctx") + } +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go b/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go new file mode 100644 index 00000000000..a698645c1ec --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go @@ -0,0 +1,65 @@ +// +build cgo + +package openssl + +/* +#include <openssl/crypto.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/conf.h> +#include <openssl/dh.h> + +static long SSL_CTX_set_tmp_dh_not_a_macro(SSL_CTX* ctx, DH *dh) { + return SSL_CTX_set_tmp_dh(ctx, dh); +} +static long PEM_read_DHparams_not_a_macro(SSL_CTX* ctx, DH *dh) { + return SSL_CTX_set_tmp_dh(ctx, dh); +} +*/ +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type DH struct { + dh *C.struct_dh_st +} + +// LoadDHParametersFromPEM loads the Diffie-Hellman parameters from +// a PEM-encoded block. +func LoadDHParametersFromPEM(pem_block []byte) (*DH, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + params := C.PEM_read_bio_DHparams(bio, nil, nil, nil) + if params == nil { + return nil, errors.New("failed reading dh parameters") + } + dhparams := &DH{dh: params} + runtime.SetFinalizer(dhparams, func(dhparams *DH) { + C.DH_free(dhparams.dh) + }) + return dhparams, nil +} + +// SetDHParameters sets the DH group (DH parameters) used to +// negotiate an emphemeral DH key during handshaking. +func (c *Ctx) SetDHParameters(dh *DH) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if int(C.SSL_CTX_set_tmp_dh_not_a_macro(c.ctx, dh.dh)) != 1 { + return errorFromErrorQueue() + } + return nil +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/digest.go b/vendor/src/github.com/spacemonkeygo/openssl/digest.go new file mode 100644 index 00000000000..44d4d001b13 --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/digest.go @@ -0,0 +1,53 @@ +// Copyright (C) 2015 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cgo + +package openssl + +// #include <openssl/evp.h> +import "C" + +import ( + "fmt" + "unsafe" +) + +// Digest represents and openssl message digest. +type Digest struct { + ptr *C.EVP_MD +} + +// GetDigestByName returns the Digest with the name or nil and an error if the +// digest was not found. +func GetDigestByName(name string) (*Digest, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + p := C.EVP_get_digestbyname(cname) + if p == nil { + return nil, fmt.Errorf("Digest %v not found", name) + } + // we can consider digests to use static mem; don't need to free + return &Digest{ptr: p}, nil +} + +// GetDigestByName returns the Digest with the NID or nil and an error if the +// digest was not found. +func GetDigestByNid(nid NID) (*Digest, error) { + sn, err := Nid2ShortName(nid) + if err != nil { + return nil, err + } + return GetDigestByName(sn) +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/key.go b/vendor/src/github.com/spacemonkeygo/openssl/key.go new file mode 100644 index 00000000000..c69a101631f --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/key.go @@ -0,0 +1,374 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cgo + +package openssl + +// #include <openssl/evp.h> +// #include <openssl/ssl.h> +// #include <openssl/conf.h> +// +// int EVP_SignInit_not_a_macro(EVP_MD_CTX *ctx, const EVP_MD *type) { +// return EVP_SignInit(ctx, type); +// } +// +// int EVP_SignUpdate_not_a_macro(EVP_MD_CTX *ctx, const void *d, +// unsigned int cnt) { +// return EVP_SignUpdate(ctx, d, cnt); +// } +// +// int EVP_VerifyInit_not_a_macro(EVP_MD_CTX *ctx, const EVP_MD *type) { +// return EVP_VerifyInit(ctx, type); +// } +// +// int EVP_VerifyUpdate_not_a_macro(EVP_MD_CTX *ctx, const void *d, +// unsigned int cnt) { +// return EVP_VerifyUpdate(ctx, d, cnt); +// } +// +// int EVP_PKEY_assign_charp(EVP_PKEY *pkey, int type, char *key) { +// return EVP_PKEY_assign(pkey, type, key); +// } +import "C" + +import ( + "errors" + "io/ioutil" + "runtime" + "unsafe" +) + +type Method *C.EVP_MD + +var ( + SHA256_Method Method = C.EVP_sha256() +) + +type PublicKey interface { + // Verifies the data signature using PKCS1.15 + VerifyPKCS1v15(method Method, data, sig []byte) error + + // MarshalPKIXPublicKeyPEM converts the public key to PEM-encoded PKIX + // format + MarshalPKIXPublicKeyPEM() (pem_block []byte, err error) + + // MarshalPKIXPublicKeyDER converts the public key to DER-encoded PKIX + // format + MarshalPKIXPublicKeyDER() (der_block []byte, err error) + + evpPKey() *C.EVP_PKEY +} + +type PrivateKey interface { + PublicKey + + // Signs the data using PKCS1.15 + SignPKCS1v15(Method, []byte) ([]byte, error) + + // MarshalPKCS1PrivateKeyPEM converts the private key to PEM-encoded PKCS1 + // format + MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error) + + // MarshalPKCS1PrivateKeyDER converts the private key to DER-encoded PKCS1 + // format + MarshalPKCS1PrivateKeyDER() (der_block []byte, err error) +} + +type pKey struct { + key *C.EVP_PKEY +} + +func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key } + +func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) { + var ctx C.EVP_MD_CTX + C.EVP_MD_CTX_init(&ctx) + defer C.EVP_MD_CTX_cleanup(&ctx) + + if 1 != C.EVP_SignInit_not_a_macro(&ctx, method) { + return nil, errors.New("signpkcs1v15: failed to init signature") + } + if len(data) > 0 { + if 1 != C.EVP_SignUpdate_not_a_macro( + &ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { + return nil, errors.New("signpkcs1v15: failed to update signature") + } + } + sig := make([]byte, C.EVP_PKEY_size(key.key)) + var sigblen C.uint + if 1 != C.EVP_SignFinal(&ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) { + return nil, errors.New("signpkcs1v15: failed to finalize signature") + } + return sig[:sigblen], nil +} + +func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error { + var ctx C.EVP_MD_CTX + C.EVP_MD_CTX_init(&ctx) + defer C.EVP_MD_CTX_cleanup(&ctx) + + if 1 != C.EVP_VerifyInit_not_a_macro(&ctx, method) { + return errors.New("verifypkcs1v15: failed to init verify") + } + if len(data) > 0 { + if 1 != C.EVP_VerifyUpdate_not_a_macro( + &ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { + return errors.New("verifypkcs1v15: failed to update verify") + } + } + if 1 != C.EVP_VerifyFinal(&ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) { + return errors.New("verifypkcs1v15: failed to finalize verify") + } + return nil +} + +func (key *pKey) MarshalPKCS1PrivateKeyPEM() (pem_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) + if rsa == nil { + return nil, errors.New("failed getting rsa key") + } + defer C.RSA_free(rsa) + if int(C.PEM_write_bio_RSAPrivateKey(bio, rsa, nil, nil, C.int(0), nil, + nil)) != 1 { + return nil, errors.New("failed dumping private key") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKCS1PrivateKeyDER() (der_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) + if rsa == nil { + return nil, errors.New("failed getting rsa key") + } + defer C.RSA_free(rsa) + if int(C.i2d_RSAPrivateKey_bio(bio, rsa)) != 1 { + return nil, errors.New("failed dumping private key der") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKIXPublicKeyPEM() (pem_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) + if rsa == nil { + return nil, errors.New("failed getting rsa key") + } + defer C.RSA_free(rsa) + if int(C.PEM_write_bio_RSA_PUBKEY(bio, rsa)) != 1 { + return nil, errors.New("failed dumping public key pem") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKIXPublicKeyDER() (der_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) + if rsa == nil { + return nil, errors.New("failed getting rsa key") + } + defer C.RSA_free(rsa) + if int(C.i2d_RSA_PUBKEY_bio(bio, rsa)) != 1 { + return nil, errors.New("failed dumping public key der") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +// LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block. +func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + rsakey := C.PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil) + if rsakey == nil { + return nil, errors.New("failed reading rsa key") + } + defer C.RSA_free(rsakey) + + // convert to PKEY + key := C.EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed converting to evp_pkey") + } + if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { + C.EVP_PKEY_free(key) + return nil, errors.New("failed converting to evp_pkey") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block. +func LoadPrivateKeyFromPEMWidthPassword(pem_block []byte, password string) ( + PrivateKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + cs := C.CString(password) + defer C.free(unsafe.Pointer(cs)) + rsakey := C.PEM_read_bio_RSAPrivateKey(bio, nil, nil, unsafe.Pointer(cs)) + if rsakey == nil { + return nil, errors.New("failed reading rsa key") + } + defer C.RSA_free(rsakey) + + // convert to PKEY + key := C.EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed converting to evp_pkey") + } + if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { + C.EVP_PKEY_free(key) + return nil, errors.New("failed converting to evp_pkey") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPublicKeyFromPEM loads a public key from a PEM-encoded block. +func LoadPublicKeyFromPEM(pem_block []byte) (PublicKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + rsakey := C.PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) + if rsakey == nil { + return nil, errors.New("failed reading rsa key") + } + defer C.RSA_free(rsakey) + + // convert to PKEY + key := C.EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed converting to evp_pkey") + } + if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { + C.EVP_PKEY_free(key) + return nil, errors.New("failed converting to evp_pkey") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPublicKeyFromDER loads a public key from a DER-encoded block. +func LoadPublicKeyFromDER(der_block []byte) (PublicKey, error) { + if len(der_block) == 0 { + return nil, errors.New("empty der block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]), + C.int(len(der_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + rsakey := C.d2i_RSA_PUBKEY_bio(bio, nil) + if rsakey == nil { + return nil, errors.New("failed reading rsa key") + } + defer C.RSA_free(rsakey) + + // convert to PKEY + key := C.EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed converting to evp_pkey") + } + if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { + C.EVP_PKEY_free(key) + return nil, errors.New("failed converting to evp_pkey") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.EVP_PKEY_free(p.key) + }) + return p, nil +} + +// GenerateRSAKey generates a new RSA private key with an exponent of 3. +func GenerateRSAKey(bits int) (PrivateKey, error) { + exponent := 3 + rsa := C.RSA_generate_key(C.int(bits), C.ulong(exponent), nil, nil) + if rsa == nil { + return nil, errors.New("failed to generate RSA key") + } + key := C.EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed to allocate EVP_PKEY") + } + if C.EVP_PKEY_assign_charp(key, C.EVP_PKEY_RSA, (*C.char)(unsafe.Pointer(rsa))) != 1 { + C.EVP_PKEY_free(key) + return nil, errors.New("failed to assign RSA key") + } + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.EVP_PKEY_free(p.key) + }) + return p, nil +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/pem_test.go b/vendor/src/github.com/spacemonkeygo/openssl/key_test.go index a79dc305fef..54752d381bf 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/pem_test.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/key_test.go @@ -132,3 +132,18 @@ func TestMarshal(t *testing.T) { t.Fatal("invalid public key der bytes") } } + +func TestGenerate(t *testing.T) { + key, err := GenerateRSAKey(2048) + if err != nil { + t.Fatal(err) + } + _, err = key.MarshalPKIXPublicKeyPEM() + if err != nil { + t.Fatal(err) + } + _, err = key.MarshalPKCS1PrivateKeyPEM() + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/net.go b/vendor/src/github.com/spacemonkeygo/openssl/net.go index 275f5c27b97..3cdd040d4d4 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/net.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/net.go @@ -77,6 +77,25 @@ const ( // This library is not nice enough to use the system certificate store by // default for you yet. func Dial(network, addr string, ctx *Ctx, flags DialFlags) (*Conn, error) { + return DialSession(network, addr, ctx, flags, nil) +} + +// DialSession will connect to network/address and then wrap the corresponding +// underlying connection with an OpenSSL client connection using context ctx. +// If flags includes InsecureSkipHostVerification, the server certificate's +// hostname will not be checked to match the hostname in addr. Otherwise, flags +// should be 0. +// +// Dial probably won't work for you unless you set a verify location or add +// some certs to the certificate store of the client context you're using. +// This library is not nice enough to use the system certificate store by +// default for you yet. +// +// If session is not nil it will be used to resume the tls state. The session +// can be retrieved from the GetSession method on the Conn. +func DialSession(network, addr string, ctx *Ctx, flags DialFlags, + session []byte) (*Conn, error) { + host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err diff --git a/vendor/src/github.com/spacemonkeygo/openssl/nid.go b/vendor/src/github.com/spacemonkeygo/openssl/nid.go new file mode 100644 index 00000000000..c80f237b605 --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/nid.go @@ -0,0 +1,199 @@ +// Copyright (C) 2014 Ryan Hileman +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +type NID int + +const ( + NID_rsadsi NID = 1 + NID_pkcs NID = 2 + NID_md2 NID = 3 + NID_md5 NID = 4 + NID_rc4 NID = 5 + NID_rsaEncryption NID = 6 + NID_md2WithRSAEncryption NID = 7 + NID_md5WithRSAEncryption NID = 8 + NID_pbeWithMD2AndDES_CBC NID = 9 + NID_pbeWithMD5AndDES_CBC NID = 10 + NID_X500 NID = 11 + NID_X509 NID = 12 + NID_commonName NID = 13 + NID_countryName NID = 14 + NID_localityName NID = 15 + NID_stateOrProvinceName NID = 16 + NID_organizationName NID = 17 + NID_organizationalUnitName NID = 18 + NID_rsa NID = 19 + NID_pkcs7 NID = 20 + NID_pkcs7_data NID = 21 + NID_pkcs7_signed NID = 22 + NID_pkcs7_enveloped NID = 23 + NID_pkcs7_signedAndEnveloped NID = 24 + NID_pkcs7_digest NID = 25 + NID_pkcs7_encrypted NID = 26 + NID_pkcs3 NID = 27 + NID_dhKeyAgreement NID = 28 + NID_des_ecb NID = 29 + NID_des_cfb64 NID = 30 + NID_des_cbc NID = 31 + NID_des_ede NID = 32 + NID_des_ede3 NID = 33 + NID_idea_cbc NID = 34 + NID_idea_cfb64 NID = 35 + NID_idea_ecb NID = 36 + NID_rc2_cbc NID = 37 + NID_rc2_ecb NID = 38 + NID_rc2_cfb64 NID = 39 + NID_rc2_ofb64 NID = 40 + NID_sha NID = 41 + NID_shaWithRSAEncryption NID = 42 + NID_des_ede_cbc NID = 43 + NID_des_ede3_cbc NID = 44 + NID_des_ofb64 NID = 45 + NID_idea_ofb64 NID = 46 + NID_pkcs9 NID = 47 + NID_pkcs9_emailAddress NID = 48 + NID_pkcs9_unstructuredName NID = 49 + NID_pkcs9_contentType NID = 50 + NID_pkcs9_messageDigest NID = 51 + NID_pkcs9_signingTime NID = 52 + NID_pkcs9_countersignature NID = 53 + NID_pkcs9_challengePassword NID = 54 + NID_pkcs9_unstructuredAddress NID = 55 + NID_pkcs9_extCertAttributes NID = 56 + NID_netscape NID = 57 + NID_netscape_cert_extension NID = 58 + NID_netscape_data_type NID = 59 + NID_des_ede_cfb64 NID = 60 + NID_des_ede3_cfb64 NID = 61 + NID_des_ede_ofb64 NID = 62 + NID_des_ede3_ofb64 NID = 63 + NID_sha1 NID = 64 + NID_sha1WithRSAEncryption NID = 65 + NID_dsaWithSHA NID = 66 + NID_dsa_2 NID = 67 + NID_pbeWithSHA1AndRC2_CBC NID = 68 + NID_id_pbkdf2 NID = 69 + NID_dsaWithSHA1_2 NID = 70 + NID_netscape_cert_type NID = 71 + NID_netscape_base_url NID = 72 + NID_netscape_revocation_url NID = 73 + NID_netscape_ca_revocation_url NID = 74 + NID_netscape_renewal_url NID = 75 + NID_netscape_ca_policy_url NID = 76 + NID_netscape_ssl_server_name NID = 77 + NID_netscape_comment NID = 78 + NID_netscape_cert_sequence NID = 79 + NID_desx_cbc NID = 80 + NID_id_ce NID = 81 + NID_subject_key_identifier NID = 82 + NID_key_usage NID = 83 + NID_private_key_usage_period NID = 84 + NID_subject_alt_name NID = 85 + NID_issuer_alt_name NID = 86 + NID_basic_constraints NID = 87 + NID_crl_number NID = 88 + NID_certificate_policies NID = 89 + NID_authority_key_identifier NID = 90 + NID_bf_cbc NID = 91 + NID_bf_ecb NID = 92 + NID_bf_cfb64 NID = 93 + NID_bf_ofb64 NID = 94 + NID_mdc2 NID = 95 + NID_mdc2WithRSA NID = 96 + NID_rc4_40 NID = 97 + NID_rc2_40_cbc NID = 98 + NID_givenName NID = 99 + NID_surname NID = 100 + NID_initials NID = 101 + NID_uniqueIdentifier NID = 102 + NID_crl_distribution_points NID = 103 + NID_md5WithRSA NID = 104 + NID_serialNumber NID = 105 + NID_title NID = 106 + NID_description NID = 107 + NID_cast5_cbc NID = 108 + NID_cast5_ecb NID = 109 + NID_cast5_cfb64 NID = 110 + NID_cast5_ofb64 NID = 111 + NID_pbeWithMD5AndCast5_CBC NID = 112 + NID_dsaWithSHA1 NID = 113 + NID_md5_sha1 NID = 114 + NID_sha1WithRSA NID = 115 + NID_dsa NID = 116 + NID_ripemd160 NID = 117 + NID_ripemd160WithRSA NID = 119 + NID_rc5_cbc NID = 120 + NID_rc5_ecb NID = 121 + NID_rc5_cfb64 NID = 122 + NID_rc5_ofb64 NID = 123 + NID_rle_compression NID = 124 + NID_zlib_compression NID = 125 + NID_ext_key_usage NID = 126 + NID_id_pkix NID = 127 + NID_id_kp NID = 128 + NID_server_auth NID = 129 + NID_client_auth NID = 130 + NID_code_sign NID = 131 + NID_email_protect NID = 132 + NID_time_stamp NID = 133 + NID_ms_code_ind NID = 134 + NID_ms_code_com NID = 135 + NID_ms_ctl_sign NID = 136 + NID_ms_sgc NID = 137 + NID_ms_efs NID = 138 + NID_ns_sgc NID = 139 + NID_delta_crl NID = 140 + NID_crl_reason NID = 141 + NID_invalidity_date NID = 142 + NID_sxnet NID = 143 + NID_pbe_WithSHA1And128BitRC4 NID = 144 + NID_pbe_WithSHA1And40BitRC4 NID = 145 + NID_pbe_WithSHA1And3_Key_TripleDES_CBC NID = 146 + NID_pbe_WithSHA1And2_Key_TripleDES_CBC NID = 147 + NID_pbe_WithSHA1And128BitRC2_CBC NID = 148 + NID_pbe_WithSHA1And40BitRC2_CBC NID = 149 + NID_keyBag NID = 150 + NID_pkcs8ShroudedKeyBag NID = 151 + NID_certBag NID = 152 + NID_crlBag NID = 153 + NID_secretBag NID = 154 + NID_safeContentsBag NID = 155 + NID_friendlyName NID = 156 + NID_localKeyID NID = 157 + NID_x509Certificate NID = 158 + NID_sdsiCertificate NID = 159 + NID_x509Crl NID = 160 + NID_pbes2 NID = 161 + NID_pbmac1 NID = 162 + NID_hmacWithSHA1 NID = 163 + NID_id_qt_cps NID = 164 + NID_id_qt_unotice NID = 165 + NID_rc2_64_cbc NID = 166 + NID_SMIMECapabilities NID = 167 + NID_pbeWithMD2AndRC2_CBC NID = 168 + NID_pbeWithMD5AndRC2_CBC NID = 169 + NID_pbeWithSHA1AndDES_CBC NID = 170 + NID_ms_ext_req NID = 171 + NID_ext_req NID = 172 + NID_name NID = 173 + NID_dnQualifier NID = 174 + NID_id_pe NID = 175 + NID_id_ad NID = 176 + NID_info_access NID = 177 + NID_ad_OCSP NID = 178 + NID_ad_ca_issuers NID = 179 + NID_OCSP_sign NID = 180 +) diff --git a/vendor/src/github.com/spacemonkeygo/openssl/pem.go b/vendor/src/github.com/spacemonkeygo/openssl/pem.go index e435480e26c..6dad5972dbd 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/pem.go +++ b/vendor/src/github.com/spacemonkeygo/openssl/pem.go @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Space Monkey, Inc. +// Copyright (C) 2014 Ryan Hileman // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,379 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build cgo - package openssl -// #include <openssl/evp.h> -// #include <openssl/ssl.h> -// #include <openssl/conf.h> -// -// void OPENSSL_free_not_a_macro(void *ref) { OPENSSL_free(ref); } -// -// int EVP_SignInit_not_a_macro(EVP_MD_CTX *ctx, const EVP_MD *type) { -// return EVP_SignInit(ctx, type); -// } -// -// int EVP_SignUpdate_not_a_macro(EVP_MD_CTX *ctx, const void *d, -// unsigned int cnt) { -// return EVP_SignUpdate(ctx, d, cnt); -// } -// -// int EVP_VerifyInit_not_a_macro(EVP_MD_CTX *ctx, const EVP_MD *type) { -// return EVP_VerifyInit(ctx, type); -// } -// -// int EVP_VerifyUpdate_not_a_macro(EVP_MD_CTX *ctx, const void *d, -// unsigned int cnt) { -// return EVP_VerifyUpdate(ctx, d, cnt); -// } -import "C" - import ( - "errors" - "io/ioutil" - "runtime" - "unsafe" + "regexp" ) -type Method *C.EVP_MD - -var ( - SHA256_Method Method = C.EVP_sha256() -) - -type PublicKey interface { - // Verifies the data signature using PKCS1.15 - VerifyPKCS1v15(method Method, data, sig []byte) error - - // MarshalPKIXPublicKeyPEM converts the public key to PEM-encoded PKIX - // format - MarshalPKIXPublicKeyPEM() (pem_block []byte, err error) - - // MarshalPKIXPublicKeyDER converts the public key to DER-encoded PKIX - // format - MarshalPKIXPublicKeyDER() (der_block []byte, err error) - - evpPKey() *C.EVP_PKEY -} - -type PrivateKey interface { - PublicKey - - // Signs the data using PKCS1.15 - SignPKCS1v15(Method, []byte) ([]byte, error) - - // MarshalPKCS1PrivateKeyPEM converts the private key to PEM-encoded PKCS1 - // format - MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error) - - // MarshalPKCS1PrivateKeyDER converts the private key to DER-encoded PKCS1 - // format - MarshalPKCS1PrivateKeyDER() (der_block []byte, err error) -} - -type pKey struct { - key *C.EVP_PKEY -} - -func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key } - -func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) { - var ctx C.EVP_MD_CTX - C.EVP_MD_CTX_init(&ctx) - defer C.EVP_MD_CTX_cleanup(&ctx) - - if 1 != C.EVP_SignInit_not_a_macro(&ctx, method) { - return nil, errors.New("signpkcs1v15: failed to init signature") - } - if len(data) > 0 { - if 1 != C.EVP_SignUpdate_not_a_macro( - &ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { - return nil, errors.New("signpkcs1v15: failed to update signature") - } - } - sig := make([]byte, C.EVP_PKEY_size(key.key)) - var sigblen C.uint - if 1 != C.EVP_SignFinal(&ctx, - ((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) { - return nil, errors.New("signpkcs1v15: failed to finalize signature") - } - return sig[:sigblen], nil -} - -func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error { - var ctx C.EVP_MD_CTX - C.EVP_MD_CTX_init(&ctx) - defer C.EVP_MD_CTX_cleanup(&ctx) - - if 1 != C.EVP_VerifyInit_not_a_macro(&ctx, method) { - return errors.New("verifypkcs1v15: failed to init verify") - } - if len(data) > 0 { - if 1 != C.EVP_VerifyUpdate_not_a_macro( - &ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { - return errors.New("verifypkcs1v15: failed to update verify") - } - } - if 1 != C.EVP_VerifyFinal(&ctx, - ((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) { - return errors.New("verifypkcs1v15: failed to finalize verify") - } - return nil -} - -func (key *pKey) MarshalPKCS1PrivateKeyPEM() (pem_block []byte, - err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) - if rsa == nil { - return nil, errors.New("failed getting rsa key") - } - defer C.RSA_free(rsa) - if int(C.PEM_write_bio_RSAPrivateKey(bio, rsa, nil, nil, C.int(0), nil, - nil)) != 1 { - return nil, errors.New("failed dumping private key") - } - return ioutil.ReadAll(asAnyBio(bio)) -} - -func (key *pKey) MarshalPKCS1PrivateKeyDER() (der_block []byte, - err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) - if rsa == nil { - return nil, errors.New("failed getting rsa key") - } - defer C.RSA_free(rsa) - if int(C.i2d_RSAPrivateKey_bio(bio, rsa)) != 1 { - return nil, errors.New("failed dumping private key der") - } - return ioutil.ReadAll(asAnyBio(bio)) -} - -func (key *pKey) MarshalPKIXPublicKeyPEM() (pem_block []byte, - err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) - if rsa == nil { - return nil, errors.New("failed getting rsa key") - } - defer C.RSA_free(rsa) - if int(C.PEM_write_bio_RSA_PUBKEY(bio, rsa)) != 1 { - return nil, errors.New("failed dumping public key pem") - } - return ioutil.ReadAll(asAnyBio(bio)) -} - -func (key *pKey) MarshalPKIXPublicKeyDER() (der_block []byte, - err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - rsa := (*C.RSA)(C.EVP_PKEY_get1_RSA(key.key)) - if rsa == nil { - return nil, errors.New("failed getting rsa key") - } - defer C.RSA_free(rsa) - if int(C.i2d_RSA_PUBKEY_bio(bio, rsa)) != 1 { - return nil, errors.New("failed dumping public key der") - } - return ioutil.ReadAll(asAnyBio(bio)) -} - -// LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block. -func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) { - if len(pem_block) == 0 { - return nil, errors.New("empty pem block") - } - bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), - C.int(len(pem_block))) - if bio == nil { - return nil, errors.New("failed creating bio") - } - defer C.BIO_free(bio) - - rsakey := C.PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil) - if rsakey == nil { - return nil, errors.New("failed reading rsa key") - } - defer C.RSA_free(rsakey) - - // convert to PKEY - key := C.EVP_PKEY_new() - if key == nil { - return nil, errors.New("failed converting to evp_pkey") - } - if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { - C.EVP_PKEY_free(key) - return nil, errors.New("failed converting to evp_pkey") - } - - p := &pKey{key: key} - runtime.SetFinalizer(p, func(p *pKey) { - C.EVP_PKEY_free(p.key) - }) - return p, nil -} - -// LoadPublicKeyFromPEM loads a public key from a PEM-encoded block. -func LoadPublicKeyFromPEM(pem_block []byte) (PublicKey, error) { - if len(pem_block) == 0 { - return nil, errors.New("empty pem block") - } - bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), - C.int(len(pem_block))) - if bio == nil { - return nil, errors.New("failed creating bio") - } - defer C.BIO_free(bio) - - rsakey := C.PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil) - if rsakey == nil { - return nil, errors.New("failed reading rsa key") - } - defer C.RSA_free(rsakey) - - // convert to PKEY - key := C.EVP_PKEY_new() - if key == nil { - return nil, errors.New("failed converting to evp_pkey") - } - if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { - C.EVP_PKEY_free(key) - return nil, errors.New("failed converting to evp_pkey") - } - - p := &pKey{key: key} - runtime.SetFinalizer(p, func(p *pKey) { - C.EVP_PKEY_free(p.key) - }) - return p, nil -} - -// LoadPublicKeyFromDER loads a public key from a DER-encoded block. -func LoadPublicKeyFromDER(der_block []byte) (PublicKey, error) { - if len(der_block) == 0 { - return nil, errors.New("empty der block") - } - bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]), - C.int(len(der_block))) - if bio == nil { - return nil, errors.New("failed creating bio") - } - defer C.BIO_free(bio) - - rsakey := C.d2i_RSA_PUBKEY_bio(bio, nil) - if rsakey == nil { - return nil, errors.New("failed reading rsa key") - } - defer C.RSA_free(rsakey) - - // convert to PKEY - key := C.EVP_PKEY_new() - if key == nil { - return nil, errors.New("failed converting to evp_pkey") - } - if C.EVP_PKEY_set1_RSA(key, (*C.struct_rsa_st)(rsakey)) != 1 { - C.EVP_PKEY_free(key) - return nil, errors.New("failed converting to evp_pkey") - } +var pemSplit *regexp.Regexp = regexp.MustCompile(`(?sm)` + + `(^-----[\s-]*?BEGIN.*?-----$` + + `.*?` + + `^-----[\s-]*?END.*?-----$)`) - p := &pKey{key: key} - runtime.SetFinalizer(p, func(p *pKey) { - C.EVP_PKEY_free(p.key) - }) - return p, nil -} - -type Certificate struct { - x *C.X509 - ref interface{} -} - -// LoadCertificateFromPEM loads an X509 certificate from a PEM-encoded block. -func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error) { - if len(pem_block) == 0 { - return nil, errors.New("empty pem block") - } - runtime.LockOSThread() - defer runtime.UnlockOSThread() - bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), - C.int(len(pem_block))) - cert := C.PEM_read_bio_X509(bio, nil, nil, nil) - C.BIO_free(bio) - if cert == nil { - return nil, errorFromErrorQueue() - } - x := &Certificate{x: cert} - runtime.SetFinalizer(x, func(x *Certificate) { - C.X509_free(x.x) - }) - return x, nil -} - -// MarshalPEM converts the X509 certificate to PEM-encoded format -func (c *Certificate) MarshalPEM() (pem_block []byte, err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - if int(C.PEM_write_bio_X509(bio, c.x)) != 1 { - return nil, errors.New("failed dumping certificate") - } - return ioutil.ReadAll(asAnyBio(bio)) -} - -// PublicKey returns the public key embedded in the X509 certificate. -func (c *Certificate) PublicKey() (PublicKey, error) { - pkey := C.X509_get_pubkey(c.x) - if pkey == nil { - return nil, errors.New("no public key found") - } - key := &pKey{key: pkey} - runtime.SetFinalizer(key, func(key *pKey) { - C.EVP_PKEY_free(key.key) - }) - return key, nil -} - -// GetSerialNumberHex returns the certificate's serial number in hex format -func (c *Certificate) GetSerialNumberHex() (serial string) { - asn1_i := C.X509_get_serialNumber(c.x) - bignum := C.ASN1_INTEGER_to_BN(asn1_i, nil) - hex := C.BN_bn2hex(bignum) - serial = C.GoString(hex) - C.BN_free(bignum) - C.OPENSSL_free_not_a_macro(unsafe.Pointer(hex)) - return -} - -func (c *Certificate) X509NamePrintEx() (out []byte, err error) { - bio := C.BIO_new(C.BIO_s_mem()) - if bio == nil { - return nil, errors.New("failed to allocate memory BIO") - } - defer C.BIO_free(bio) - name := C.X509_get_subject_name(c.x) - // TODO, pass in flags instead of using this hardcoded one - if int(C.X509_NAME_print_ex(bio, name, 0, C.XN_FLAG_RFC2253)) < 0 { - return nil, errors.New("failed formatting subject") +func SplitPEM(data []byte) [][]byte { + var results [][]byte + for _, block := range pemSplit.FindAll(data, -1) { + results = append(results, block) } - return ioutil.ReadAll(asAnyBio(bio)) + return results } diff --git a/vendor/src/github.com/spacemonkeygo/openssl/sni.c b/vendor/src/github.com/spacemonkeygo/openssl/sni.c new file mode 100644 index 00000000000..5398da869b8 --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/sni.c @@ -0,0 +1,23 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <openssl/ssl.h> +#include "_cgo_export.h" +#include <stdio.h> + +int sni_cb(SSL *con, int *ad, void *arg) { + SSL_CTX* ssl_ctx = ssl_ctx = SSL_get_SSL_CTX(con); + void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx()); + return sni_cb_thunk(p, con, ad, arg); +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go b/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go new file mode 100644 index 00000000000..ee3b1a8bbaf --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go @@ -0,0 +1,23 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import "fmt" + +// We can implemant SNI rfc6066 (http://tools.ietf.org/html/rfc6066) on the server side using foolowing callback. +// You should implement context storage (tlsCtxStorage) by your self. +func ExampleSetTLSExtServernameCallback() { + fmt.Println("Hello") +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/ssl.go b/vendor/src/github.com/spacemonkeygo/openssl/ssl.go new file mode 100644 index 00000000000..d6120e15d99 --- /dev/null +++ b/vendor/src/github.com/spacemonkeygo/openssl/ssl.go @@ -0,0 +1,167 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cgo + +package openssl + +/* +#include <openssl/crypto.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/conf.h> + +static long SSL_set_options_not_a_macro(SSL* ssl, long options) { + return SSL_set_options(ssl, options); +} + +static long SSL_get_options_not_a_macro(SSL* ssl) { + return SSL_get_options(ssl); +} + +static long SSL_clear_options_not_a_macro(SSL* ssl, long options) { + return SSL_clear_options(ssl, options); +} + +extern int verify_ssl_cb(int ok, X509_STORE_CTX* store); +*/ +import "C" + +import ( + "os" + "unsafe" +) + +type SSLTLSExtErr int + +var ( + ssl_idx = C.SSL_get_ex_new_index(0, nil, nil, nil, nil) +) + +//export get_ssl_idx +func get_ssl_idx() C.int { + return ssl_idx +} + +type SSL struct { + ssl *C.SSL + verify_cb VerifyCallback +} + +//export verify_ssl_cb_thunk +func verify_ssl_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: verify callback panic'd: %v", err) + os.Exit(1) + } + }() + verify_cb := (*SSL)(p).verify_cb + // set up defaults just in case verify_cb is nil + if verify_cb != nil { + store := &CertificateStoreCtx{ctx: ctx} + if verify_cb(ok == 1, store) { + ok = 1 + } else { + ok = 0 + } + } + return ok +} + +// GetOptions returns SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) GetOptions() Options { + return Options(C.SSL_get_options_not_a_macro(s.ssl)) +} + +// SetOptions sets SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) SetOptions(options Options) Options { + return Options(C.SSL_set_options_not_a_macro(s.ssl, C.long(options))) +} + +// ClearOptions clear SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) ClearOptions(options Options) Options { + return Options(C.SSL_clear_options_not_a_macro(s.ssl, C.long(options))) +} + +// SetVerify controls peer verification settings. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerify(options VerifyOptions, verify_cb VerifyCallback) { + s.verify_cb = verify_cb + if verify_cb != nil { + C.SSL_set_verify(s.ssl, C.int(options), (*[0]byte)(C.verify_ssl_cb)) + } else { + C.SSL_set_verify(s.ssl, C.int(options), nil) + } +} + +// SetVerifyMode controls peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyMode(options VerifyOptions) { + s.SetVerify(options, s.verify_cb) +} + +// SetVerifyCallback controls peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyCallback(verify_cb VerifyCallback) { + s.SetVerify(s.VerifyMode(), s.verify_cb) +} + +// GetVerifyCallback returns callback function. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) GetVerifyCallback() VerifyCallback { + return s.verify_cb +} + +// VerifyMode returns peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) VerifyMode() VerifyOptions { + return VerifyOptions(C.SSL_get_verify_mode(s.ssl)) +} + +// SetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyDepth(depth int) { + C.SSL_set_verify_depth(s.ssl, C.int(depth)) +} + +// GetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) GetVerifyDepth() int { + return int(C.SSL_get_verify_depth(s.ssl)) +} + +//export sni_cb_thunk +func sni_cb_thunk(p unsafe.Pointer, con *C.SSL, ad unsafe.Pointer, arg unsafe.Pointer) C.int { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: verify callback sni panic'd: %v", err) + os.Exit(1) + } + }() + + sni_cb := (*Ctx)(p).sni_cb + + s := &SSL{ssl: con} + // This attaches a pointer to our SSL struct into the SNI callback. + C.SSL_set_ex_data(s.ssl, get_ssl_idx(), unsafe.Pointer(s)) + + // Note: this is ctx.sni_cb, not C.sni_cb + return C.int(sni_cb(s)) +} diff --git a/vendor/src/github.com/spacemonkeygo/openssl/verify.c b/vendor/src/github.com/spacemonkeygo/openssl/verify.c index bfc626812cd..d55866c4cf0 100644 --- a/vendor/src/github.com/spacemonkeygo/openssl/verify.c +++ b/vendor/src/github.com/spacemonkeygo/openssl/verify.c @@ -14,12 +14,18 @@ #include <openssl/ssl.h> #include "_cgo_export.h" -#include <stdio.h> int verify_cb(int ok, X509_STORE_CTX* store) { SSL* ssl = (SSL *)X509_STORE_CTX_get_app_data(store); - SSL_CTX* ssl_ctx = ssl_ctx = SSL_get_SSL_CTX(ssl); + SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx()); // get the pointer to the go Ctx object and pass it back into the thunk return verify_cb_thunk(p, ok, store); } + +int verify_ssl_cb(int ok, X509_STORE_CTX* store) { + SSL* ssl = (SSL *)X509_STORE_CTX_get_app_data(store); + void* p = SSL_get_ex_data(ssl, get_ssl_idx()); + // get the pointer to the go Ctx object and pass it back into the thunk + return verify_ssl_cb_thunk(p, ok, store); +} |