summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl')
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/LICENSE191
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/README.md26
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/bio.go355
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/build.go23
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert.go407
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go139
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go355
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go307
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/conn.go625
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx.go831
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go48
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go65
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/digest.go53
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/engine.go52
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/fips.go22
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.c367
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.go127
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/http.go61
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init.go155
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_posix.go64
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_windows.go60
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key.go374
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key_test.go149
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/net.go134
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/nid.go199
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/oracle_stubs.go162
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/password.c10
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/pem.go32
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1.go99
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1_test.go111
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256.go92
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256_test.go109
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni.c23
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go23
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl.go167
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl_test.go633
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/errors.go50
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/future.go79
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/verify.c31
-rw-r--r--src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/version.go22
40 files changed, 6832 insertions, 0 deletions
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/LICENSE b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/LICENSE
new file mode 100644
index 00000000000..37ec93a14fd
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/README.md b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/README.md
new file mode 100644
index 00000000000..6bd3383a0e8
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/README.md
@@ -0,0 +1,26 @@
+# OpenSSL bindings for Go
+
+Please see http://godoc.org/github.com/spacemonkeygo/openssl for more info
+
+### License
+
+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.
+
+### Using on Windows
+1. Install [mingw-w64](http://mingw-w64.sourceforge.net/)
+2. Install [pkg-config-lite](http://sourceforge.net/projects/pkgconfiglite)
+3. Build (or install precompiled) openssl for mingw32-w64
+4. Set __PKG\_CONFIG\_PATH__ to the directory containing openssl.pc
+ (i.e. c:\mingw64\mingw64\lib\pkgconfig)
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/bio.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/bio.go
new file mode 100644
index 00000000000..1be93aaa23a
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/bio.go
@@ -0,0 +1,355 @@
+// 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 <string.h>
+#include <openssl/bio.h>
+
+extern int cbioNew(BIO *b);
+static int cbioFree(BIO *b) {
+ return 1;
+}
+
+extern int writeBioWrite(BIO *b, char *buf, int size);
+extern long writeBioCtrl(BIO *b, int cmd, long arg1, void *arg2);
+static int writeBioPuts(BIO *b, const char *str) {
+ return writeBioWrite(b, (char*)str, (int)strlen(str));
+}
+
+extern int readBioRead(BIO *b, char *buf, int size);
+extern long readBioCtrl(BIO *b, int cmd, long arg1, void *arg2);
+
+static BIO_METHOD writeBioMethod = {
+ BIO_TYPE_SOURCE_SINK,
+ "Go Write BIO",
+ (int (*)(BIO *, const char *, int))writeBioWrite,
+ NULL,
+ writeBioPuts,
+ NULL,
+ writeBioCtrl,
+ cbioNew,
+ cbioFree,
+ NULL};
+
+static BIO_METHOD* BIO_s_writeBio() { return &writeBioMethod; }
+
+static BIO_METHOD readBioMethod = {
+ BIO_TYPE_SOURCE_SINK,
+ "Go Read BIO",
+ NULL,
+ readBioRead,
+ NULL,
+ NULL,
+ readBioCtrl,
+ cbioNew,
+ cbioFree,
+ NULL};
+
+static BIO_METHOD* BIO_s_readBio() { return &readBioMethod; }
+*/
+import "C"
+
+import (
+ "errors"
+ "io"
+ "reflect"
+ "sync"
+ "unsafe"
+)
+
+const (
+ SSLRecordSize = 16 * 1024
+)
+
+func nonCopyGoBytes(ptr uintptr, length int) []byte {
+ var slice []byte
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
+ header.Cap = length
+ header.Len = length
+ header.Data = ptr
+ return slice
+}
+
+func nonCopyCString(data *C.char, size C.int) []byte {
+ return nonCopyGoBytes(uintptr(unsafe.Pointer(data)), int(size))
+}
+
+//export cbioNew
+func cbioNew(b *C.BIO) C.int {
+ b.shutdown = 1
+ b.init = 1
+ b.num = -1
+ b.ptr = nil
+ b.flags = 0
+ return 1
+}
+
+type writeBio struct {
+ data_mtx sync.Mutex
+ op_mtx sync.Mutex
+ buf []byte
+ release_buffers bool
+}
+
+func loadWritePtr(b *C.BIO) *writeBio {
+ return (*writeBio)(unsafe.Pointer(b.ptr))
+}
+
+func bioClearRetryFlags(b *C.BIO) {
+ // from BIO_clear_retry_flags and BIO_clear_flags
+ b.flags &= ^(C.BIO_FLAGS_RWS | C.BIO_FLAGS_SHOULD_RETRY)
+}
+
+func bioSetRetryRead(b *C.BIO) {
+ // from BIO_set_retry_read and BIO_set_flags
+ b.flags |= (C.BIO_FLAGS_READ | C.BIO_FLAGS_SHOULD_RETRY)
+}
+
+//export writeBioWrite
+func writeBioWrite(b *C.BIO, data *C.char, size C.int) (rc C.int) {
+ defer func() {
+ if err := recover(); err != nil {
+ logger.Critf("openssl: writeBioWrite panic'd: %v", err)
+ rc = -1
+ }
+ }()
+ ptr := loadWritePtr(b)
+ if ptr == nil || data == nil || size < 0 {
+ return -1
+ }
+ ptr.data_mtx.Lock()
+ defer ptr.data_mtx.Unlock()
+ bioClearRetryFlags(b)
+ ptr.buf = append(ptr.buf, nonCopyCString(data, size)...)
+ return size
+}
+
+//export writeBioCtrl
+func writeBioCtrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) (
+ rc C.long) {
+ defer func() {
+ if err := recover(); err != nil {
+ logger.Critf("openssl: writeBioCtrl panic'd: %v", err)
+ rc = -1
+ }
+ }()
+ switch cmd {
+ case C.BIO_CTRL_WPENDING:
+ return writeBioPending(b)
+ case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH:
+ return 1
+ default:
+ return 0
+ }
+}
+
+func writeBioPending(b *C.BIO) C.long {
+ ptr := loadWritePtr(b)
+ if ptr == nil {
+ return 0
+ }
+ ptr.data_mtx.Lock()
+ defer ptr.data_mtx.Unlock()
+ return C.long(len(ptr.buf))
+}
+
+func (b *writeBio) WriteTo(w io.Writer) (rv int64, err error) {
+ b.op_mtx.Lock()
+ defer b.op_mtx.Unlock()
+
+ // write whatever data we currently have
+ b.data_mtx.Lock()
+ data := b.buf
+ b.data_mtx.Unlock()
+
+ if len(data) == 0 {
+ return 0, nil
+ }
+ n, err := w.Write(data)
+
+ // subtract however much data we wrote from the buffer
+ b.data_mtx.Lock()
+ b.buf = b.buf[:copy(b.buf, b.buf[n:])]
+ if b.release_buffers && len(b.buf) == 0 {
+ b.buf = nil
+ }
+ b.data_mtx.Unlock()
+
+ return int64(n), err
+}
+
+func (self *writeBio) Disconnect(b *C.BIO) {
+ if loadWritePtr(b) == self {
+ b.ptr = nil
+ }
+}
+
+func (b *writeBio) MakeCBIO() *C.BIO {
+ rv := C.BIO_new(C.BIO_s_writeBio())
+ rv.ptr = unsafe.Pointer(b)
+ return rv
+}
+
+type readBio struct {
+ data_mtx sync.Mutex
+ op_mtx sync.Mutex
+ buf []byte
+ eof bool
+ release_buffers bool
+}
+
+func loadReadPtr(b *C.BIO) *readBio {
+ return (*readBio)(unsafe.Pointer(b.ptr))
+}
+
+//export readBioRead
+func readBioRead(b *C.BIO, data *C.char, size C.int) (rc C.int) {
+ defer func() {
+ if err := recover(); err != nil {
+ logger.Critf("openssl: readBioRead panic'd: %v", err)
+ rc = -1
+ }
+ }()
+ ptr := loadReadPtr(b)
+ if ptr == nil || size < 0 {
+ return -1
+ }
+ ptr.data_mtx.Lock()
+ defer ptr.data_mtx.Unlock()
+ bioClearRetryFlags(b)
+ if len(ptr.buf) == 0 {
+ if ptr.eof {
+ return 0
+ }
+ bioSetRetryRead(b)
+ return -1
+ }
+ if size == 0 || data == nil {
+ return C.int(len(ptr.buf))
+ }
+ n := copy(nonCopyCString(data, size), ptr.buf)
+ ptr.buf = ptr.buf[:copy(ptr.buf, ptr.buf[n:])]
+ if ptr.release_buffers && len(ptr.buf) == 0 {
+ ptr.buf = nil
+ }
+ return C.int(n)
+}
+
+//export readBioCtrl
+func readBioCtrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) (
+ rc C.long) {
+
+ defer func() {
+ if err := recover(); err != nil {
+ logger.Critf("openssl: readBioCtrl panic'd: %v", err)
+ rc = -1
+ }
+ }()
+ switch cmd {
+ case C.BIO_CTRL_PENDING:
+ return readBioPending(b)
+ case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH:
+ return 1
+ default:
+ return 0
+ }
+}
+
+func readBioPending(b *C.BIO) C.long {
+ ptr := loadReadPtr(b)
+ if ptr == nil {
+ return 0
+ }
+ ptr.data_mtx.Lock()
+ defer ptr.data_mtx.Unlock()
+ return C.long(len(ptr.buf))
+}
+
+func (b *readBio) ReadFromOnce(r io.Reader) (n int, err error) {
+ b.op_mtx.Lock()
+ defer b.op_mtx.Unlock()
+
+ // make sure we have a destination that fits at least one SSL record
+ b.data_mtx.Lock()
+ if cap(b.buf) < len(b.buf)+SSLRecordSize {
+ new_buf := make([]byte, len(b.buf), len(b.buf)+SSLRecordSize)
+ copy(new_buf, b.buf)
+ b.buf = new_buf
+ }
+ dst := b.buf[len(b.buf):cap(b.buf)]
+ dst_slice := b.buf
+ b.data_mtx.Unlock()
+
+ n, err = r.Read(dst)
+ b.data_mtx.Lock()
+ defer b.data_mtx.Unlock()
+ if n > 0 {
+ if len(dst_slice) != len(b.buf) {
+ // someone shrunk the buffer, so we read in too far ahead and we
+ // need to slide backwards
+ copy(b.buf[len(b.buf):len(b.buf)+n], dst)
+ }
+ b.buf = b.buf[:len(b.buf)+n]
+ }
+ return n, err
+}
+
+func (b *readBio) MakeCBIO() *C.BIO {
+ rv := C.BIO_new(C.BIO_s_readBio())
+ rv.ptr = unsafe.Pointer(b)
+ return rv
+}
+
+func (self *readBio) Disconnect(b *C.BIO) {
+ if loadReadPtr(b) == self {
+ b.ptr = nil
+ }
+}
+
+func (b *readBio) MarkEOF() {
+ b.data_mtx.Lock()
+ defer b.data_mtx.Unlock()
+ b.eof = true
+}
+
+type anyBio C.BIO
+
+func asAnyBio(b *C.BIO) *anyBio { return (*anyBio)(b) }
+
+func (b *anyBio) Read(buf []byte) (n int, err error) {
+ if len(buf) == 0 {
+ return 0, nil
+ }
+ n = int(C.BIO_read((*C.BIO)(b), unsafe.Pointer(&buf[0]), C.int(len(buf))))
+ if n <= 0 {
+ return 0, io.EOF
+ }
+ return n, nil
+}
+
+func (b *anyBio) Write(buf []byte) (written int, err error) {
+ if len(buf) == 0 {
+ return 0, nil
+ }
+ n := int(C.BIO_write((*C.BIO)(b), unsafe.Pointer(&buf[0]),
+ C.int(len(buf))))
+ if n != len(buf) {
+ return n, errors.New("BIO write failed")
+ }
+ return n, nil
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/build.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/build.go
new file mode 100644
index 00000000000..dd72651d3ea
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/build.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.
+
+// +build cgo
+
+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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert.go
new file mode 100644
index 00000000000..61637c649fa
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/cert_test.go
new file mode 100644
index 00000000000..c32883ba4eb
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go
new file mode 100644
index 00000000000..12662707f54
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers.go
@@ -0,0 +1,355 @@
+// 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>
+//
+// int EVP_CIPHER_block_size_not_a_macro(EVP_CIPHER *c) {
+// return EVP_CIPHER_block_size(c);
+// }
+//
+// int EVP_CIPHER_key_length_not_a_macro(EVP_CIPHER *c) {
+// return EVP_CIPHER_key_length(c);
+// }
+//
+// int EVP_CIPHER_iv_length_not_a_macro(EVP_CIPHER *c) {
+// return EVP_CIPHER_iv_length(c);
+// }
+//
+// int EVP_CIPHER_nid_not_a_macro(EVP_CIPHER *c) {
+// return EVP_CIPHER_nid(c);
+// }
+//
+// int EVP_CIPHER_CTX_block_size_not_a_macro(EVP_CIPHER_CTX *ctx) {
+// return EVP_CIPHER_CTX_block_size(ctx);
+// }
+//
+// int EVP_CIPHER_CTX_key_length_not_a_macro(EVP_CIPHER_CTX *ctx) {
+// return EVP_CIPHER_CTX_key_length(ctx);
+// }
+//
+// int EVP_CIPHER_CTX_iv_length_not_a_macro(EVP_CIPHER_CTX *ctx) {
+// return EVP_CIPHER_CTX_iv_length(ctx);
+// }
+//
+// const EVP_CIPHER *EVP_CIPHER_CTX_cipher_not_a_macro(EVP_CIPHER_CTX *ctx) {
+// return EVP_CIPHER_CTX_cipher(ctx);
+// }
+import "C"
+
+import (
+ "errors"
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+const (
+ GCM_TAG_MAXLEN = 16
+)
+
+type CipherCtx interface {
+ Cipher() *Cipher
+ BlockSize() int
+ KeySize() int
+ IVSize() int
+}
+
+type Cipher struct {
+ ptr *C.EVP_CIPHER
+}
+
+func (c *Cipher) Nid() NID {
+ return NID(C.EVP_CIPHER_nid_not_a_macro(c.ptr))
+}
+
+func (c *Cipher) ShortName() (string, error) {
+ return Nid2ShortName(c.Nid())
+}
+
+func (c *Cipher) BlockSize() int {
+ return int(C.EVP_CIPHER_block_size_not_a_macro(c.ptr))
+}
+
+func (c *Cipher) KeySize() int {
+ return int(C.EVP_CIPHER_key_length_not_a_macro(c.ptr))
+}
+
+func (c *Cipher) IVSize() int {
+ return int(C.EVP_CIPHER_iv_length_not_a_macro(c.ptr))
+}
+
+func Nid2ShortName(nid NID) (string, error) {
+ sn := C.OBJ_nid2sn(C.int(nid))
+ if sn == nil {
+ return "", fmt.Errorf("NID %d not found", nid)
+ }
+ return C.GoString(sn), nil
+}
+
+func GetCipherByName(name string) (*Cipher, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ p := C.EVP_get_cipherbyname(cname)
+ if p == nil {
+ return nil, fmt.Errorf("Cipher %v not found", name)
+ }
+ // we can consider ciphers to use static mem; don't need to free
+ return &Cipher{ptr: p}, nil
+}
+
+func GetCipherByNid(nid NID) (*Cipher, error) {
+ sn, err := Nid2ShortName(nid)
+ if err != nil {
+ return nil, err
+ }
+ return GetCipherByName(sn)
+}
+
+type cipherCtx struct {
+ ctx *C.EVP_CIPHER_CTX
+}
+
+func newCipherCtx() (*cipherCtx, error) {
+ cctx := C.EVP_CIPHER_CTX_new()
+ if cctx == nil {
+ return nil, errors.New("failed to allocate cipher context")
+ }
+ ctx := &cipherCtx{cctx}
+ runtime.SetFinalizer(ctx, func(ctx *cipherCtx) {
+ C.EVP_CIPHER_CTX_free(ctx.ctx)
+ })
+ return ctx, nil
+}
+
+func (ctx *cipherCtx) applyKeyAndIV(key, iv []byte) error {
+ var kptr, iptr *C.uchar
+ if key != nil {
+ if len(key) != ctx.KeySize() {
+ return fmt.Errorf("bad key size (%d bytes instead of %d)",
+ len(key), ctx.KeySize())
+ }
+ kptr = (*C.uchar)(&key[0])
+ }
+ if iv != nil {
+ if len(iv) != ctx.IVSize() {
+ return fmt.Errorf("bad IV size (%d bytes instead of %d)",
+ len(iv), ctx.IVSize())
+ }
+ iptr = (*C.uchar)(&iv[0])
+ }
+ if kptr != nil || iptr != nil {
+ 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")
+ }
+ }
+ return nil
+}
+
+func (ctx *cipherCtx) Cipher() *Cipher {
+ return &Cipher{ptr: C.EVP_CIPHER_CTX_cipher_not_a_macro(ctx.ctx)}
+}
+
+func (ctx *cipherCtx) BlockSize() int {
+ return int(C.EVP_CIPHER_CTX_block_size_not_a_macro(ctx.ctx))
+}
+
+func (ctx *cipherCtx) KeySize() int {
+ return int(C.EVP_CIPHER_CTX_key_length_not_a_macro(ctx.ctx))
+}
+
+func (ctx *cipherCtx) IVSize() int {
+ return int(C.EVP_CIPHER_CTX_iv_length_not_a_macro(ctx.ctx))
+}
+
+func (ctx *cipherCtx) setCtrl(code, arg int) error {
+ res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), nil)
+ if res != 1 {
+ return fmt.Errorf("failed to set code %d to %d [result %d]",
+ code, arg, res)
+ }
+ return nil
+}
+
+func (ctx *cipherCtx) setCtrlBytes(code, arg int, value []byte) error {
+ res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg),
+ unsafe.Pointer(&value[0]))
+ if res != 1 {
+ return fmt.Errorf("failed to set code %d with arg %d to %x [result %d]",
+ code, arg, value, res)
+ }
+ return nil
+}
+
+func (ctx *cipherCtx) getCtrlInt(code, arg int) (int, error) {
+ var returnVal C.int
+ res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg),
+ unsafe.Pointer(&returnVal))
+ if res != 1 {
+ return 0, fmt.Errorf("failed to get code %d with arg %d [result %d]",
+ code, arg, res)
+ }
+ return int(returnVal), nil
+}
+
+func (ctx *cipherCtx) getCtrlBytes(code, arg, expectsize int) ([]byte, error) {
+ returnVal := make([]byte, expectsize)
+ res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg),
+ unsafe.Pointer(&returnVal[0]))
+ if res != 1 {
+ return nil, fmt.Errorf("failed to get code %d with arg %d [result %d]",
+ code, arg, res)
+ }
+ return returnVal, nil
+}
+
+type EncryptionCipherCtx interface {
+ CipherCtx
+
+ // pass in plaintext, get back ciphertext. can be called
+ // multiple times as needed
+ EncryptUpdate(input []byte) ([]byte, error)
+
+ // call after all plaintext has been passed in; may return
+ // additional ciphertext if needed to finish off a block
+ // or extra padding information
+ EncryptFinal() ([]byte, error)
+}
+
+type DecryptionCipherCtx interface {
+ CipherCtx
+
+ // pass in ciphertext, get back plaintext. can be called
+ // multiple times as needed
+ DecryptUpdate(input []byte) ([]byte, error)
+
+ // call after all ciphertext has been passed in; may return
+ // additional plaintext if needed to finish off a block
+ DecryptFinal() ([]byte, error)
+}
+
+type encryptionCipherCtx struct {
+ *cipherCtx
+}
+
+type decryptionCipherCtx struct {
+ *cipherCtx
+}
+
+func newEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) (
+ *encryptionCipherCtx, error) {
+ if c == nil {
+ return nil, errors.New("null cipher not allowed")
+ }
+ ctx, err := newCipherCtx()
+ if err != nil {
+ return nil, err
+ }
+ var eptr *C.ENGINE
+ if e != nil {
+ eptr = e.e
+ }
+ if 1 != C.EVP_EncryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) {
+ return nil, errors.New("failed to initialize cipher context")
+ }
+ err = ctx.applyKeyAndIV(key, iv)
+ if err != nil {
+ return nil, err
+ }
+ return &encryptionCipherCtx{cipherCtx: ctx}, nil
+}
+
+func newDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) (
+ *decryptionCipherCtx, error) {
+ if c == nil {
+ return nil, errors.New("null cipher not allowed")
+ }
+ ctx, err := newCipherCtx()
+ if err != nil {
+ return nil, err
+ }
+ var eptr *C.ENGINE
+ if e != nil {
+ eptr = e.e
+ }
+ if 1 != C.EVP_DecryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) {
+ return nil, errors.New("failed to initialize cipher context")
+ }
+ err = ctx.applyKeyAndIV(key, iv)
+ if err != nil {
+ return nil, err
+ }
+ return &decryptionCipherCtx{cipherCtx: ctx}, nil
+}
+
+func NewEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) (
+ EncryptionCipherCtx, error) {
+ return newEncryptionCipherCtx(c, e, key, iv)
+}
+
+func NewDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) (
+ DecryptionCipherCtx, error) {
+ return newDecryptionCipherCtx(c, e, key, iv)
+}
+
+func (ctx *encryptionCipherCtx) EncryptUpdate(input []byte) ([]byte, error) {
+ outbuf := make([]byte, len(input)+ctx.BlockSize())
+ outlen := C.int(len(outbuf))
+ res := C.EVP_EncryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen,
+ (*C.uchar)(&input[0]), C.int(len(input)))
+ if res != 1 {
+ return nil, fmt.Errorf("failed to encrypt [result %d]", res)
+ }
+ return outbuf[:outlen], nil
+}
+
+func (ctx *decryptionCipherCtx) DecryptUpdate(input []byte) ([]byte, error) {
+ outbuf := make([]byte, len(input)+ctx.BlockSize())
+ outlen := C.int(len(outbuf))
+ res := C.EVP_DecryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen,
+ (*C.uchar)(&input[0]), C.int(len(input)))
+ if res != 1 {
+ return nil, fmt.Errorf("failed to decrypt [result %d]", res)
+ }
+ return outbuf[:outlen], nil
+}
+
+func (ctx *encryptionCipherCtx) EncryptFinal() ([]byte, error) {
+ outbuf := make([]byte, ctx.BlockSize())
+ var outlen C.int
+ if 1 != C.EVP_EncryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) {
+ return nil, errors.New("encryption failed")
+ }
+ return outbuf[:outlen], nil
+}
+
+func (ctx *decryptionCipherCtx) DecryptFinal() ([]byte, error) {
+ outbuf := make([]byte, ctx.BlockSize())
+ var outlen C.int
+ if 1 != C.EVP_DecryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) {
+ // this may mean the tag failed to verify- all previous plaintext
+ // returned must be considered faked and invalid
+ return nil, errors.New("decryption failed")
+ }
+ return outbuf[:outlen], nil
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go
new file mode 100644
index 00000000000..d1d430b1e15
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ciphers_test.go
@@ -0,0 +1,307 @@
+// 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 !darwin
+
+package openssl
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "testing"
+)
+
+func expectError(t *testing.T, err error, msg string) {
+ if err == nil {
+ t.Fatalf("Expected error containing %#v, but got none", msg)
+ }
+ if !strings.Contains(err.Error(), msg) {
+ t.Fatalf("Expected error containing %#v, but got %s", msg, err)
+ }
+}
+
+func TestBadInputs(t *testing.T) {
+ _, err := NewGCMEncryptionCipherCtx(256, nil,
+ []byte("abcdefghijklmnopqrstuvwxyz"), nil)
+ expectError(t, err, "bad key size")
+ _, err = NewGCMEncryptionCipherCtx(128, nil,
+ []byte("abcdefghijklmnopqrstuvwxyz"), nil)
+ expectError(t, err, "bad key size")
+ _, err = NewGCMEncryptionCipherCtx(200, nil,
+ []byte("abcdefghijklmnopqrstuvwxy"), nil)
+ expectError(t, err, "unknown block size")
+ c, err := GetCipherByName("AES-128-CBC")
+ if err != nil {
+ t.Fatal("Could not look up AES-128-CBC")
+ }
+ _, err = NewEncryptionCipherCtx(c, nil, []byte("abcdefghijklmnop"),
+ []byte("abc"))
+ expectError(t, err, "bad IV size")
+}
+
+func doEncryption(key, iv, aad, plaintext []byte, blocksize, bufsize int) (
+ ciphertext, tag []byte, err error) {
+ ectx, err := NewGCMEncryptionCipherCtx(blocksize, nil, key, iv)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Failed making GCM encryption ctx: %s", err)
+ }
+ err = ectx.ExtraData(aad)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Failed to add authenticated data: %s",
+ err)
+ }
+ plainb := bytes.NewBuffer(plaintext)
+ cipherb := new(bytes.Buffer)
+ for plainb.Len() > 0 {
+ moar, err := ectx.EncryptUpdate(plainb.Next(bufsize))
+ if err != nil {
+ return nil, nil, fmt.Errorf("Failed to perform an encryption: %s",
+ err)
+ }
+ cipherb.Write(moar)
+ }
+ moar, err := ectx.EncryptFinal()
+ if err != nil {
+ return nil, nil, fmt.Errorf("Failed to finalize encryption: %s", err)
+ }
+ cipherb.Write(moar)
+ tag, err = ectx.GetTag()
+ if err != nil {
+ return nil, nil, fmt.Errorf("Failed to get GCM tag: %s", err)
+ }
+ return cipherb.Bytes(), tag, nil
+}
+
+func doDecryption(key, iv, aad, ciphertext, tag []byte, blocksize,
+ bufsize int) (plaintext []byte, err error) {
+ dctx, err := NewGCMDecryptionCipherCtx(blocksize, nil, key, iv)
+ if err != nil {
+ return nil, fmt.Errorf("Failed making GCM decryption ctx: %s", err)
+ }
+ aadbuf := bytes.NewBuffer(aad)
+ for aadbuf.Len() > 0 {
+ err = dctx.ExtraData(aadbuf.Next(bufsize))
+ if err != nil {
+ return nil, fmt.Errorf("Failed to add authenticated data: %s", err)
+ }
+ }
+ plainb := new(bytes.Buffer)
+ cipherb := bytes.NewBuffer(ciphertext)
+ for cipherb.Len() > 0 {
+ moar, err := dctx.DecryptUpdate(cipherb.Next(bufsize))
+ if err != nil {
+ return nil, fmt.Errorf("Failed to perform a decryption: %s", err)
+ }
+ plainb.Write(moar)
+ }
+ err = dctx.SetTag(tag)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to set expected GCM tag: %s", err)
+ }
+ moar, err := dctx.DecryptFinal()
+ if err != nil {
+ return nil, fmt.Errorf("Failed to finalize decryption: %s", err)
+ }
+ plainb.Write(moar)
+ return plainb.Bytes(), nil
+}
+
+func checkEqual(t *testing.T, output []byte, original string) {
+ output_s := string(output)
+ if output_s != original {
+ t.Fatalf("output != original! %#v != %#v", output_s, original)
+ }
+}
+
+func TestGCM(t *testing.T) {
+ aad := []byte("foo bar baz")
+ key := []byte("nobody can guess this i'm sure..") // len=32
+ iv := []byte("just a bunch of bytes")
+ plaintext := "Long long ago, in a land far away..."
+
+ blocksizes_to_test := []int{256, 192, 128}
+
+ // best for this to have no common factors with blocksize, so that the
+ // buffering layer inside the CIPHER_CTX gets exercised
+ bufsize := 33
+
+ if len(plaintext)%8 == 0 {
+ plaintext += "!" // make sure padding is exercised
+ }
+
+ for _, bsize := range blocksizes_to_test {
+ subkey := key[:bsize/8]
+ ciphertext, tag, err := doEncryption(subkey, iv, aad, []byte(plaintext),
+ bsize, bufsize)
+ if err != nil {
+ t.Fatalf("Encryption with b=%d: %s", bsize, err)
+ }
+ plaintext_out, err := doDecryption(subkey, iv, aad, ciphertext, tag,
+ bsize, bufsize)
+ if err != nil {
+ t.Fatalf("Decryption with b=%d: %s", bsize, err)
+ }
+ checkEqual(t, plaintext_out, plaintext)
+ }
+}
+
+func TestGCMWithNoAAD(t *testing.T) {
+ key := []byte("0000111122223333")
+ iv := []byte("9999")
+ plaintext := "ABORT ABORT ABORT DANGAR"
+
+ ciphertext, tag, err := doEncryption(key, iv, nil, []byte(plaintext),
+ 128, 32)
+ if err != nil {
+ t.Fatal("Encryption failure:", err)
+ }
+ plaintext_out, err := doDecryption(key, iv, nil, ciphertext, tag, 128, 129)
+ if err != nil {
+ t.Fatal("Decryption failure:", err)
+ }
+ checkEqual(t, plaintext_out, plaintext)
+}
+
+func TestBadTag(t *testing.T) {
+ key := []byte("abcdefghijklmnop")
+ iv := []byte("v7239qjfv3qr793fuaj")
+ plaintext := "The red rooster has flown the coop I REPEAT" +
+ "the red rooster has flown the coop!!1!"
+
+ ciphertext, tag, err := doEncryption(key, iv, nil, []byte(plaintext),
+ 128, 32)
+ if err != nil {
+ t.Fatal("Encryption failure:", err)
+ }
+ // flip the last bit
+ tag[len(tag)-1] ^= 1
+ plaintext_out, err := doDecryption(key, iv, nil, ciphertext, tag, 128, 129)
+ if err == nil {
+ t.Fatal("Expected error for bad tag, but got none")
+ }
+ // flip it back, try again just to make sure
+ tag[len(tag)-1] ^= 1
+ plaintext_out, err = doDecryption(key, iv, nil, ciphertext, tag, 128, 129)
+ if err != nil {
+ t.Fatal("Decryption failure:", err)
+ }
+ checkEqual(t, plaintext_out, plaintext)
+}
+
+func TestBadCiphertext(t *testing.T) {
+ key := []byte("hard boiled eggs & bacon")
+ iv := []byte("x") // it's not a very /good/ IV, is it
+ aad := []byte("mu")
+ plaintext := "Roger roger bingo charlie, we have a niner fourteen tango"
+
+ ciphertext, tag, err := doEncryption(key, iv, aad, []byte(plaintext),
+ 192, 1)
+ if err != nil {
+ t.Fatal("Encryption failure:", err)
+ }
+ // flip the last bit
+ ciphertext[len(ciphertext)-1] ^= 1
+ plaintext_out, err := doDecryption(key, iv, aad, ciphertext, tag, 192, 192)
+ if err == nil {
+ t.Fatal("Expected error for bad ciphertext, but got none")
+ }
+ // flip it back, try again just to make sure
+ ciphertext[len(ciphertext)-1] ^= 1
+ plaintext_out, err = doDecryption(key, iv, aad, ciphertext, tag, 192, 192)
+ if err != nil {
+ t.Fatal("Decryption failure:", err)
+ }
+ checkEqual(t, plaintext_out, plaintext)
+}
+
+func TestBadAAD(t *testing.T) {
+ key := []byte("Ive got a lovely buncha coconuts")
+ iv := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")
+ aad := []byte("Hi i am a plain")
+ plaintext := "Whatever."
+
+ ciphertext, tag, err := doEncryption(key, iv, aad, []byte(plaintext),
+ 256, 256)
+ if err != nil {
+ t.Fatal("Encryption failure:", err)
+ }
+ // flip the last bit
+ aad[len(aad)-1] ^= 1
+ plaintext_out, err := doDecryption(key, iv, aad, ciphertext, tag, 256, 256)
+ if err == nil {
+ t.Fatal("Expected error for bad AAD, but got none")
+ }
+ // flip it back, try again just to make sure
+ aad[len(aad)-1] ^= 1
+ plaintext_out, err = doDecryption(key, iv, aad, ciphertext, tag, 256, 256)
+ if err != nil {
+ t.Fatal("Decryption failure:", err)
+ }
+ 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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/conn.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/conn.go
new file mode 100644
index 00000000000..afc73a50ae3
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/conn.go
@@ -0,0 +1,625 @@
+// 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 <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"
+ "sync"
+ "time"
+ "unsafe"
+
+ "github.com/spacemonkeygo/openssl/utils"
+)
+
+var (
+ zeroReturn = errors.New("zero return")
+ wantRead = errors.New("want read")
+ wantWrite = errors.New("want write")
+ tryAgain = errors.New("try again")
+)
+
+type Conn struct {
+ conn net.Conn
+ ssl *C.SSL
+ ctx *Ctx // for gc
+ into_ssl *readBio
+ from_ssl *writeBio
+ is_shutdown bool
+ mtx sync.Mutex
+ 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()
+ ssl := C.SSL_new(ctx)
+ if ssl == nil {
+ return nil, errorFromErrorQueue()
+ }
+ return ssl, nil
+}
+
+func newConn(conn net.Conn, ctx *Ctx) (*Conn, error) {
+ ssl, err := newSSL(ctx.ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ into_ssl := &readBio{}
+ from_ssl := &writeBio{}
+
+ if ctx.GetMode()&ReleaseBuffers > 0 {
+ into_ssl.release_buffers = true
+ from_ssl.release_buffers = true
+ }
+
+ into_ssl_cbio := into_ssl.MakeCBIO()
+ from_ssl_cbio := from_ssl.MakeCBIO()
+ if into_ssl_cbio == nil || from_ssl_cbio == nil {
+ // these frees are null safe
+ C.BIO_free(into_ssl_cbio)
+ C.BIO_free(from_ssl_cbio)
+ C.SSL_free(ssl)
+ return nil, errors.New("failed to allocate memory BIO")
+ }
+
+ // the ssl object takes ownership of these objects now
+ C.SSL_set_bio(ssl, into_ssl_cbio, from_ssl_cbio)
+
+ c := &Conn{
+ conn: conn,
+ ssl: ssl,
+ ctx: ctx,
+ into_ssl: into_ssl,
+ from_ssl: from_ssl}
+ runtime.SetFinalizer(c, func(c *Conn) {
+ c.into_ssl.Disconnect(into_ssl_cbio)
+ c.from_ssl.Disconnect(from_ssl_cbio)
+ C.SSL_free(c.ssl)
+ })
+ return c, nil
+}
+
+// Client wraps an existing stream connection and puts it in the connect state
+// for any subsequent handshakes.
+//
+// IMPORTANT NOTE: if you use this method instead of Dial to construct an SSL
+// connection, you are responsible for verifying the peer's hostname.
+// Otherwise, you are vulnerable to MITM attacks.
+//
+// Client also does not set up SNI for you like Dial does.
+//
+// Client connections 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.
+func Client(conn net.Conn, ctx *Ctx) (*Conn, error) {
+ c, err := newConn(conn, ctx)
+ if err != nil {
+ return nil, err
+ }
+ C.SSL_set_connect_state(c.ssl)
+ return c, nil
+}
+
+// Server wraps an existing stream connection and puts it in the accept state
+// for any subsequent handshakes.
+func Server(conn net.Conn, ctx *Ctx) (*Conn, error) {
+ c, err := newConn(conn, ctx)
+ if err != nil {
+ return nil, err
+ }
+ C.SSL_set_accept_state(c.ssl)
+ 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)
+ if n == 0 && err == nil {
+ continue
+ }
+ if err == io.EOF {
+ c.into_ssl.MarkEOF()
+ return c.Close()
+ }
+ return err
+ }
+}
+
+func (c *Conn) flushOutputBuffer() error {
+ _, err := c.from_ssl.WriteTo(c.conn)
+ return err
+}
+
+func (c *Conn) getErrorHandler(rv C.int, errno error) func() error {
+ errcode := C.SSL_get_error(c.ssl, rv)
+ switch errcode {
+ case C.SSL_ERROR_ZERO_RETURN:
+ return func() error {
+ c.Close()
+ return io.ErrUnexpectedEOF
+ }
+ case C.SSL_ERROR_WANT_READ:
+ go c.flushOutputBuffer()
+ if c.want_read_future != nil {
+ want_read_future := c.want_read_future
+ return func() error {
+ _, err := want_read_future.Get()
+ return err
+ }
+ }
+ c.want_read_future = utils.NewFuture()
+ want_read_future := c.want_read_future
+ return func() (err error) {
+ defer func() {
+ c.mtx.Lock()
+ c.want_read_future = nil
+ c.mtx.Unlock()
+ want_read_future.Set(nil, err)
+ }()
+ err = c.fillInputBuffer()
+ if err != nil {
+ return err
+ }
+ return tryAgain
+ }
+ case C.SSL_ERROR_WANT_WRITE:
+ return func() error {
+ err := c.flushOutputBuffer()
+ if err != nil {
+ return err
+ }
+ return tryAgain
+ }
+ case C.SSL_ERROR_SYSCALL:
+ var err error
+ if C.ERR_peek_error() == 0 {
+ switch rv {
+ case 0:
+ err = errors.New("protocol-violating EOF")
+ case -1:
+ err = errno
+ default:
+ err = errorFromErrorQueue()
+ }
+ } else {
+ err = errorFromErrorQueue()
+ }
+ return func() error { return err }
+ default:
+ err := errorFromErrorQueue()
+ return func() error { return err }
+ }
+}
+
+func (c *Conn) handleError(errcb func() error) error {
+ if errcb != nil {
+ return errcb()
+ }
+ return nil
+}
+
+func (c *Conn) handshake() func() error {
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ if c.is_shutdown {
+ return func() error { return io.ErrUnexpectedEOF }
+ }
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ rv, errno := C.SSL_do_handshake(c.ssl)
+ if rv > 0 {
+ return nil
+ }
+ return c.getErrorHandler(rv, errno)
+}
+
+// Handshake performs an SSL handshake. If a handshake is not manually
+// triggered, it will run before the first I/O on the encrypted stream.
+func (c *Conn) Handshake() error {
+ err := tryAgain
+ for err == tryAgain {
+ err = c.handleError(c.handshake())
+ }
+ go c.flushOutputBuffer()
+ return err
+}
+
+// PeerCertificate returns the Certificate of the peer with which you're
+// communicating. Only valid after a handshake.
+func (c *Conn) PeerCertificate() (*Certificate, error) {
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ if c.is_shutdown {
+ return nil, errors.New("connection closed")
+ }
+ x := C.SSL_get_peer_certificate(c.ssl)
+ if x == nil {
+ return nil, errors.New("no peer certificate found")
+ }
+ cert := &Certificate{x: x}
+ runtime.SetFinalizer(cert, func(cert *Certificate) {
+ C.X509_free(cert.x)
+ })
+ return cert, nil
+}
+
+// PeerCertificateChain returns the certificate chain of the peer. If called on
+// the client side, the stack also contains the peer's certificate; if called
+// on the server side, the peer's certificate must be obtained separately using
+// PeerCertificate.
+func (c *Conn) PeerCertificateChain() (rv []*Certificate, err error) {
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ if c.is_shutdown {
+ return nil, errors.New("connection closed")
+ }
+ sk := C.SSL_get_peer_cert_chain(c.ssl)
+ if sk == nil {
+ return nil, errors.New("no peer certificates found")
+ }
+ sk_num := int(C.sk_X509_num_not_a_macro(sk))
+ rv = make([]*Certificate, 0, sk_num)
+ for i := 0; i < sk_num; i++ {
+ x := C.sk_X509_value_not_a_macro(sk, C.int(i))
+ // ref holds on to the underlying connection memory so we don't need to
+ // worry about incrementing refcounts manually or freeing the X509
+ rv = append(rv, &Certificate{x: x, ref: c})
+ }
+ return rv, nil
+}
+
+// GetVerifyResult gets result of peer certificate verification
+// SSL_get_verify_result() returns the result of the verification of the X509
+// certificate presented by the peer, if any. See
+// https://www.openssl.org/docs/ssl/SSL_get_verify_result.html
+func (c *Conn) GetVerifyResults() error {
+ result := C.SSL_get_verify_result(c.ssl)
+ if int(result) != 0 {
+ return errors.New(C.GoString(
+ C.X509_verify_cert_error_string(result)))
+ }
+ return nil
+}
+
+type ConnectionState struct {
+ Certificate *Certificate
+ 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
+}
+
+func (c *Conn) shutdown() func() error {
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ rv, errno := C.SSL_shutdown(c.ssl)
+ if rv > 0 {
+ return nil
+ }
+ if rv == 0 {
+ // The OpenSSL docs say that in this case, the shutdown is not
+ // finished, and we should call SSL_shutdown() a second time, if a
+ // bidirectional shutdown is going to be performed. Further, the
+ // output of SSL_get_error may be misleading, as an erroneous
+ // SSL_ERROR_SYSCALL may be flagged even though no error occurred.
+ // So, TODO: revisit bidrectional shutdown, possibly trying again.
+ // Note: some broken clients won't engage in bidirectional shutdown
+ // without tickling them to close by sending a TCP_FIN packet, or
+ // shutting down the write-side of the connection.
+ return nil
+ } else {
+ return c.getErrorHandler(rv, errno)
+ }
+}
+
+func (c *Conn) shutdownLoop() error {
+ err := tryAgain
+ shutdown_tries := 0
+ for err == tryAgain {
+ shutdown_tries = shutdown_tries + 1
+ err = c.handleError(c.shutdown())
+ if err == nil {
+ return c.flushOutputBuffer()
+ }
+ if err == tryAgain && shutdown_tries >= 2 {
+ return errors.New("shutdown requested a third time?")
+ }
+ }
+ if err == io.ErrUnexpectedEOF {
+ err = nil
+ }
+ return err
+}
+
+// Close shuts down the SSL connection and closes the underlying wrapped
+// connection.
+func (c *Conn) Close() error {
+ c.mtx.Lock()
+ if c.is_shutdown {
+ c.mtx.Unlock()
+ return nil
+ }
+ c.is_shutdown = true
+ c.mtx.Unlock()
+ var errs utils.ErrorGroup
+ errs.Add(c.shutdownLoop())
+ errs.Add(c.conn.Close())
+ return errs.Finalize()
+}
+
+func (c *Conn) read(b []byte) (int, func() error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ if c.is_shutdown {
+ return 0, func() error { return io.EOF }
+ }
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ rv, errno := C.SSL_read(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
+ if rv > 0 {
+ return int(rv), nil
+ }
+ return 0, c.getErrorHandler(rv, errno)
+}
+
+// Read reads up to len(b) bytes into b. It returns the number of bytes read
+// and an error if applicable. io.EOF is returned when the caller can expect
+// to see no more data.
+func (c *Conn) Read(b []byte) (n int, err error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ err = tryAgain
+ for err == tryAgain {
+ n, errcb := c.read(b)
+ err = c.handleError(errcb)
+ if err == nil {
+ go c.flushOutputBuffer()
+ return n, nil
+ }
+ if err == io.ErrUnexpectedEOF {
+ err = io.EOF
+ }
+ }
+ return 0, err
+}
+
+func (c *Conn) write(b []byte) (int, func() error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+ if c.is_shutdown {
+ err := errors.New("connection closed")
+ return 0, func() error { return err }
+ }
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ rv, errno := C.SSL_write(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b)))
+ if rv > 0 {
+ return int(rv), nil
+ }
+ return 0, c.getErrorHandler(rv, errno)
+}
+
+// Write will encrypt the contents of b and write it to the underlying stream.
+// Performance will be vastly improved if the size of b is a multiple of
+// SSLRecordSize.
+func (c *Conn) Write(b []byte) (written int, err error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ err = tryAgain
+ for err == tryAgain {
+ n, errcb := c.write(b)
+ err = c.handleError(errcb)
+ if err == nil {
+ return n, c.flushOutputBuffer()
+ }
+ }
+ return 0, err
+}
+
+// VerifyHostname pulls the PeerCertificate and calls VerifyHostname on the
+// certificate.
+func (c *Conn) VerifyHostname(host string) error {
+ cert, err := c.PeerCertificate()
+ if err != nil {
+ return err
+ }
+ return cert.VerifyHostname(host)
+}
+
+// LocalAddr returns the underlying connection's local address
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the underlying connection's remote address
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetDeadline calls SetDeadline on the underlying connection.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline calls SetReadDeadline on the underlying connection.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline calls SetWriteDeadline on the underlying connection.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return c.conn.SetWriteDeadline(t)
+}
+
+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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx.go
new file mode 100644
index 00000000000..74422f290a3
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx.go
@@ -0,0 +1,831 @@
+// 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>
+#include <openssl/x509.h>
+
+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);
+}
+
+static long SSL_CTX_get_mode_not_a_macro(SSL_CTX* ctx) {
+ return SSL_CTX_get_mode(ctx);
+}
+
+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);
+}
+
+static long SSL_CTX_add_extra_chain_cert_not_a_macro(SSL_CTX* ctx, X509 *cert) {
+ return SSL_CTX_add_extra_chain_cert(ctx, cert);
+}
+
+#ifndef SSL_MODE_RELEASE_BUFFERS
+#define SSL_MODE_RELEASE_BUFFERS 0
+#endif
+
+#ifndef SSL_OP_NO_COMPRESSION
+#define SSL_OP_NO_COMPRESSION 0
+#endif
+
+static const SSL_METHOD *OUR_TLSv1_1_method() {
+#if OPENSSL_VERSION_NUMBER > 0x1000100fL && defined(TLS1_1_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX)
+ return TLSv1_1_method();
+#else
+ return NULL;
+#endif
+}
+
+static const SSL_METHOD *OUR_TLSv1_2_method() {
+#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;
+
+static void sk_X509_NAME_pop_free_not_a_macro(STACK_OF_X509_NAME_not_a_macro st) {
+ sk_X509_NAME_pop_free(st, X509_NAME_free);
+}
+
+extern int password_cb(char *buf, int size, int rwflag, void *password);
+*/
+import "C"
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "time"
+ "unsafe"
+
+ "github.com/spacemonkeygo/spacelog"
+)
+
+var (
+ ssl_ctx_idx = C.SSL_CTX_get_ex_new_index(0, nil, nil, nil, nil)
+
+ logger = spacelog.GetLogger()
+)
+
+type Ctx struct {
+ ctx *C.SSL_CTX
+ cert *Certificate
+ chain []*Certificate
+ key PrivateKey
+ verify_cb VerifyCallback
+ sni_cb TLSExtServernameCallback
+}
+
+//export get_ssl_ctx_idx
+func get_ssl_ctx_idx() C.int {
+ return ssl_ctx_idx
+}
+
+func newCtx(method *C.SSL_METHOD) (*Ctx, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ ctx := C.SSL_CTX_new(method)
+ if ctx == nil {
+ return nil, errorFromErrorQueue()
+ }
+ c := &Ctx{ctx: ctx}
+ C.SSL_CTX_set_ex_data(ctx, get_ssl_ctx_idx(), unsafe.Pointer(c))
+ runtime.SetFinalizer(c, func(c *Ctx) {
+ C.SSL_CTX_free(c.ctx)
+ })
+ return c, nil
+}
+
+type SSLVersion int
+
+const (
+ 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
+)
+
+// NewCtxWithVersion creates an SSL context that is specific to the provided
+// SSL version. See http://www.openssl.org/docs/ssl/SSL_CTX_new.html for more.
+func NewCtxWithVersion(version SSLVersion) (*Ctx, error) {
+ var method *C.SSL_METHOD
+ switch version {
+ case TLSv1:
+ method = C.TLSv1_method()
+ case TLSv1_1:
+ method = C.OUR_TLSv1_1_method()
+ case TLSv1_2:
+ method = C.OUR_TLSv1_2_method()
+ case AnyVersion:
+ method = C.SSLv23_method()
+ }
+ if method == nil {
+ return nil, errors.New("unknown ssl/tls version")
+ }
+ return newCtx(method)
+}
+
+// NewCtx creates a context that supports any TLS version 1.0 and newer.
+func NewCtx() (*Ctx, error) {
+ c, err := NewCtxWithVersion(AnyVersion)
+ if err == nil {
+ c.SetOptions(NoSSLv2 | NoSSLv3)
+ }
+ return c, err
+}
+
+// NewCtxFromFiles calls NewCtx, loads the provided files, and configures the
+// context to use them.
+func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) {
+ ctx, err := NewCtx()
+ if err != nil {
+ return nil, err
+ }
+
+ cert_bytes, err := ioutil.ReadFile(cert_file)
+ if err != nil {
+ return nil, err
+ }
+
+ 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
+ }
+
+ err = ctx.UseCertificate(cert)
+ if err != nil {
+ 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
+ }
+
+ key, err := LoadPrivateKeyFromPEM(key_bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ err = ctx.UsePrivateKey(key)
+ if err != nil {
+ return nil, err
+ }
+
+ return ctx, nil
+}
+
+// EllipticCurve repesents the ASN.1 OID of an elliptic curve.
+// see https://www.openssl.org/docs/apps/ecparam.html for a list of implemented curves.
+type EllipticCurve int
+
+const (
+ // P-256: X9.62/SECG curve over a 256 bit prime field
+ Prime256v1 EllipticCurve = C.NID_X9_62_prime256v1
+ // P-384: NIST/SECG curve over a 384 bit prime field
+ Secp384r1 EllipticCurve = C.NID_secp384r1
+)
+
+// UseCertificate configures the context to present the given certificate to
+// peers.
+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()
+ }
+ return nil
+}
+
+// UseCertificateChainFromFile loads a certificate chain from file into ctx.
+// The certificates must be in PEM format and must be sorted starting with the
+// subject's certificate (actual client or server certificate), followed by
+// intermediate CA certificates if applicable, and ending at the highest level
+// (root) CA. See
+// https://www.openssl.org/docs/ssl/SSL_CTX_use_certificate.html
+func (c *Ctx) UseCertificateChainFile(cert_file string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_cert_file *C.char
+ if cert_file != "" {
+ c_cert_file = C.CString(cert_file)
+ defer C.free(unsafe.Pointer(c_cert_file))
+ }
+ if int(C.SSL_CTX_use_certificate_chain_file(c.ctx, c_cert_file)) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+// UsePrivateKeyFile adds the first private key found in file to the *Ctx, c. The
+// formatting type of the certificate must be specified from the known types
+// FiletypePEM, and FiletypeASN1
+func (c *Ctx) UsePrivateKeyFile(key_file string, file_type Filetypes) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_key_file *C.char
+ if key_file != "" {
+ c_key_file = C.CString(key_file)
+ defer C.free(unsafe.Pointer(c_key_file))
+ }
+ if int(C.SSL_CTX_use_PrivateKey_file(c.ctx, c_key_file, C.int(file_type))) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+func (c *Ctx) UsePrivateKeyFileWithPassword(key_file string, file_type Filetypes, password string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_key_file *C.char
+
+ c_pwd := C.CString(password)
+ defer C.free(unsafe.Pointer(c_pwd))
+ C.SSL_CTX_set_default_passwd_cb_userdata(c.ctx, unsafe.Pointer(c_pwd))
+ C.SSL_CTX_set_default_passwd_cb(c.ctx, (*C.pem_password_cb)(C.password_cb))
+
+ if key_file != "" {
+ c_key_file = C.CString(key_file)
+ defer C.free(unsafe.Pointer(c_key_file))
+ }
+ if int(C.SSL_CTX_use_PrivateKey_file(c.ctx, c_key_file, C.int(file_type))) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+// CheckPrivateKey verifies that the private key agrees with the corresponding
+// public key in the certificate
+func (c *Ctx) CheckPrivateKey() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if int(C.SSL_CTX_check_private_key(c.ctx)) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+type StackOfX509Name struct {
+ stack C.STACK_OF_X509_NAME_not_a_macro
+ // shared indicates weather we are the sole owner of this pointer, and implies
+ // weather we should or shouldn't free the underlying data structure
+ // when this go data structure goes out of scope
+ shared bool
+}
+
+// LoadClientCAFile reads certificates from file and returns a StackOfX509Name
+// with the subject names found. See
+// https://www.openssl.org/docs/ssl/SSL_load_client_CA_file.html
+func LoadClientCAFile(ca_file string) (*StackOfX509Name, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_ca_file *C.char
+ if ca_file != "" {
+ c_ca_file = C.CString(ca_file)
+ defer C.free(unsafe.Pointer(c_ca_file))
+ }
+ stack := C.SSL_load_client_CA_file(c_ca_file)
+ if stack == nil {
+ return nil, errorFromErrorQueue()
+ }
+ caList := StackOfX509Name{
+ stack: stack,
+ shared: false,
+ }
+ runtime.SetFinalizer(&caList, func(c *StackOfX509Name) {
+ if !c.shared {
+ C.sk_X509_NAME_pop_free_not_a_macro(c.stack)
+ }
+ })
+ return &caList, nil
+}
+
+// SetClientCAList sets the list of CAs sent to the client when requesting a
+// client certificate for Ctx. See
+// https://www.openssl.org/docs/ssl/SSL_CTX_set_client_CA_list.html
+func (c *Ctx) SetClientCAList(caList *StackOfX509Name) {
+ C.SSL_CTX_set_client_CA_list(c.ctx, caList.stack)
+ caList.shared = true
+}
+
+// AddChainCertificate adds a certificate to the chain presented in the
+// handshake.
+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
+}
+
+// UsePrivateKey configures the context to use the given private key for SSL
+// handshakes.
+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()
+ }
+ return nil
+}
+
+type CertificateStore struct {
+ store *C.X509_STORE
+ // 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
+// used for peer validation.
+func (c *Ctx) GetCertificateStore() *CertificateStore {
+ // we don't need to dealloc the cert store pointer here, because it points
+ // to a ctx internal. so we do need to keep the ctx around
+ return &CertificateStore{
+ store: C.SSL_CTX_get_cert_store(c.ctx),
+ ctx: c}
+}
+
+// AddCertificate marks the provided Certificate as a trusted certificate in
+// the given 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()
+ }
+ return nil
+}
+
+type X509VerificationFlag int
+
+func (s *CertificateStore) SetFlags(flags X509VerificationFlag) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ if int(C.X509_STORE_set_flags(s.store, C.ulong(flags))) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+// See https://www.openssl.org/docs/crypto/X509_VERIFY_PARAM_set_flags.html
+const (
+ CBIssuerCheck X509VerificationFlag = C.X509_V_FLAG_CB_ISSUER_CHECK
+ UseCheckTime X509VerificationFlag = C.X509_V_FLAG_USE_CHECK_TIME
+ CRLCheck X509VerificationFlag = C.X509_V_FLAG_CRL_CHECK
+ CRLCheckAll X509VerificationFlag = C.X509_V_FLAG_CRL_CHECK_ALL
+ IgnoreCritical X509VerificationFlag = C.X509_V_FLAG_IGNORE_CRITICAL
+ X509Strict X509VerificationFlag = C.X509_V_FLAG_X509_STRICT
+ AllowProxyCerts X509VerificationFlag = C.X509_V_FLAG_ALLOW_PROXY_CERTS
+ PolicyCheck X509VerificationFlag = C.X509_V_FLAG_POLICY_CHECK
+ ExplicitPolicy X509VerificationFlag = C.X509_V_FLAG_EXPLICIT_POLICY
+ InhibitAny X509VerificationFlag = C.X509_V_FLAG_INHIBIT_ANY
+ InhibitMap X509VerificationFlag = C.X509_V_FLAG_INHIBIT_MAP
+ NotifyPolicy X509VerificationFlag = C.X509_V_FLAG_NOTIFY_POLICY
+ // ExtendedCRLSupport X509VerificationFlag = C.X509_V_FLAG_EXTENDED_CRL_SUPPORT
+ // UseDeltas X509VerificationFlag = C.X509_V_FLAG_USE_DELTAS
+ // CheckSsSignature X509VerificationFlag = C.X509_V_FLAG_CHECK_SS_SIGNATURE
+ // TrustedFirst X509VerificationFlag = C.X509_V_FLAG_TRUSTED_FIRST
+ PolicyMask X509VerificationFlag = C.X509_V_FLAG_POLICY_MASK
+)
+
+type CertificateStoreLookup struct {
+ lookup *C.X509_LOOKUP
+ store *CertificateStore
+}
+
+// an X509LookupMethod is required to build a a CertificateStoreLookup in a
+// CertificateStore. The X509LookupMethod indicates the type or functionality
+// of the CertificateStoreLookup
+type X509LookupMethod *C.X509_LOOKUP_METHOD
+
+// CertificateStoreLookups with X509LookupFile methods look for certs in a file
+func X509LookupFile() X509LookupMethod {
+ return X509LookupMethod(C.X509_LOOKUP_file())
+}
+
+// CertificateStoreLookups with X509LookupHashDir methods look for certs in a
+// directory
+func X509LookupHashDir() X509LookupMethod {
+ return X509LookupMethod(C.X509_LOOKUP_hash_dir())
+}
+
+// AddLookup creates a CertificateStoreLookup of type X509LookupMethod in the
+// CertificateStore
+func (s *CertificateStore) AddLookup(method X509LookupMethod) (*CertificateStoreLookup, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var lookup *C.X509_LOOKUP
+ lookup = C.X509_STORE_add_lookup(s.store, method)
+ if lookup != nil {
+ return &CertificateStoreLookup{
+ lookup: lookup,
+ store: s,
+ }, nil
+ }
+ return nil, errorFromErrorQueue()
+}
+
+// LoadCRLFile adds a file to a CertificateStoreLookup in the
+// CertificateStore
+// I suspect that the CertificateStoreLookup needs to have been created with
+// X509LookupFile as the lookup method
+func (l *CertificateStoreLookup) LoadCRLFile(crl_file string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_crl_file *C.char
+ if crl_file != "" {
+ c_crl_file = C.CString(crl_file)
+ defer C.free(unsafe.Pointer(c_crl_file))
+ }
+ if int(C.X509_load_crl_file(l.lookup, c_crl_file, C.X509_FILETYPE_PEM)) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+type CertificateStoreCtx struct {
+ ctx *C.X509_STORE_CTX
+ 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 {
+ return nil
+ }
+ return fmt.Errorf("openssl: %s",
+ C.GoString(C.X509_verify_cert_error_string(C.long(code))))
+}
+
+func (self *CertificateStoreCtx) Depth() int {
+ return int(C.X509_STORE_CTX_get_error_depth(self.ctx))
+}
+
+// the certicate returned is only valid for the lifetime of the underlying
+// X509_STORE_CTX
+func (self *CertificateStoreCtx) GetCurrentCert() *Certificate {
+ x509 := C.X509_STORE_CTX_get_current_cert(self.ctx)
+ if x509 == nil {
+ return nil
+ }
+ // add a ref
+ C.CRYPTO_add_not_a_macro(&x509.references, 1, C.CRYPTO_LOCK_X509)
+ cert := &Certificate{
+ x: x509,
+ }
+ runtime.SetFinalizer(cert, func(cert *Certificate) {
+ C.X509_free(cert.x)
+ })
+ return cert
+}
+
+// LoadVerifyLocations tells the context to trust all certificate authorities
+// provided in either the ca_file or the ca_path.
+// See http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html for
+// more.
+func (c *Ctx) LoadVerifyLocations(ca_file string, ca_path string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ var c_ca_file, c_ca_path *C.char
+ if ca_file != "" {
+ c_ca_file = C.CString(ca_file)
+ defer C.free(unsafe.Pointer(c_ca_file))
+ }
+ if ca_path != "" {
+ c_ca_path = C.CString(ca_path)
+ defer C.free(unsafe.Pointer(c_ca_path))
+ }
+ if C.SSL_CTX_load_verify_locations(c.ctx, c_ca_file, c_ca_path) != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+type Options uint
+
+const (
+ // NoCompression is only valid if you are using OpenSSL 1.0.1 or newer
+ NoCompression Options = C.SSL_OP_NO_COMPRESSION
+ NoSSLv2 Options = C.SSL_OP_NO_SSLv2
+ NoSSLv3 Options = C.SSL_OP_NO_SSLv3
+ NoTLSv1 Options = C.SSL_OP_NO_TLSv1
+ CipherServerPreference Options = C.SSL_OP_CIPHER_SERVER_PREFERENCE
+ NoSessionResumptionOrRenegotiation Options = C.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ OpAll Options = C.SSL_OP_ALL
+)
+
+// SetOptions sets context options. See
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
+func (c *Ctx) SetOptions(options Options) Options {
+ return Options(C.SSL_CTX_set_options_not_a_macro(
+ 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 (
+ // ReleaseBuffers is only valid if you are using OpenSSL 1.0.1 or newer
+ ReleaseBuffers Modes = C.SSL_MODE_RELEASE_BUFFERS
+ AutoRetry Modes = C.SSL_MODE_AUTO_RETRY
+)
+
+// SetMode sets context modes. See
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
+func (c *Ctx) SetMode(modes Modes) Modes {
+ return Modes(C.SSL_CTX_set_mode_not_a_macro(c.ctx, C.long(modes)))
+}
+
+// GetMode returns context modes. See
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html
+func (c *Ctx) GetMode() Modes {
+ return Modes(C.SSL_CTX_get_mode_not_a_macro(c.ctx))
+}
+
+type VerifyOptions int
+
+const (
+ VerifyNone VerifyOptions = C.SSL_VERIFY_NONE
+ VerifyPeer VerifyOptions = C.SSL_VERIFY_PEER
+ VerifyFailIfNoPeerCert VerifyOptions = C.SSL_VERIFY_FAIL_IF_NO_PEER_CERT
+ VerifyClientOnce VerifyOptions = C.SSL_VERIFY_CLIENT_ONCE
+)
+
+type Filetypes int
+
+const (
+ FiletypePEM Filetypes = C.SSL_FILETYPE_PEM
+ FiletypeASN1 Filetypes = C.SSL_FILETYPE_ASN1
+)
+
+type VerifyCallback func(ok bool, store *CertificateStoreCtx) bool
+
+//export verify_cb_thunk
+func verify_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 := (*Ctx)(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
+}
+
+// SetVerify controls peer verification settings. See
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
+func (c *Ctx) SetVerify(options VerifyOptions, verify_cb VerifyCallback) {
+ c.verify_cb = verify_cb
+ if verify_cb != nil {
+ C.SSL_CTX_set_verify(c.ctx, C.int(options), (*[0]byte)(C.verify_cb))
+ } else {
+ C.SSL_CTX_set_verify(c.ctx, C.int(options), nil)
+ }
+}
+
+func (c *Ctx) SetVerifyMode(options VerifyOptions) {
+ c.SetVerify(options, c.verify_cb)
+}
+
+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))
+}
+
+// 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 (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()
+ var ptr *C.uchar
+ if len(session_id) > 0 {
+ ptr = (*C.uchar)(unsafe.Pointer(&session_id[0]))
+ }
+ if int(C.SSL_CTX_set_session_id_context(c.ctx, ptr,
+ C.uint(len(session_id)))) == 0 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+// SetCipherList sets the list of available ciphers. The format of the list is
+// described at http://www.openssl.org/docs/apps/ciphers.html, but see
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_cipher_list.html for more.
+func (c *Ctx) SetCipherList(list string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ clist := C.CString(list)
+ defer C.free(unsafe.Pointer(clist))
+ if int(C.SSL_CTX_set_cipher_list(c.ctx, clist)) == 0 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
+
+type SessionCacheModes int
+
+const (
+ SessionCacheOff SessionCacheModes = C.SSL_SESS_CACHE_OFF
+ SessionCacheClient SessionCacheModes = C.SSL_SESS_CACHE_CLIENT
+ SessionCacheServer SessionCacheModes = C.SSL_SESS_CACHE_SERVER
+ SessionCacheBoth SessionCacheModes = C.SSL_SESS_CACHE_BOTH
+ NoAutoClear SessionCacheModes = C.SSL_SESS_CACHE_NO_AUTO_CLEAR
+ NoInternalLookup SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
+ NoInternalStore SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL_STORE
+ NoInternal SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL
+)
+
+// SetSessionCacheMode enables or disables session caching. See
+// http://www.openssl.org/docs/ssl/SSL_CTX_set_session_cache_mode.html
+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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ctx_test.go
new file mode 100644
index 00000000000..9644e518bf3
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/dhparam.go
new file mode 100644
index 00000000000..a698645c1ec
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/digest.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/digest.go
new file mode 100644
index 00000000000..44d4d001b13
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/engine.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/engine.go
new file mode 100644
index 00000000000..7a175b70f7c
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/engine.go
@@ -0,0 +1,52 @@
+// 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/engine.h"
+*/
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+type Engine struct {
+ e *C.ENGINE
+}
+
+func EngineById(name string) (*Engine, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ e := &Engine{
+ e: C.ENGINE_by_id(cname),
+ }
+ if e.e == nil {
+ return nil, fmt.Errorf("engine %s missing", name)
+ }
+ if C.ENGINE_init(e.e) == 0 {
+ C.ENGINE_free(e.e)
+ return nil, fmt.Errorf("engine %s not initialized", name)
+ }
+ runtime.SetFinalizer(e, func(e *Engine) {
+ C.ENGINE_finish(e.e)
+ C.ENGINE_free(e.e)
+ })
+ return e, nil
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/fips.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/fips.go
new file mode 100644
index 00000000000..cc463f17a18
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/fips.go
@@ -0,0 +1,22 @@
+// +build cgo
+// +build -darwin
+
+package openssl
+
+/*
+#include <openssl/ssl.h>
+*/
+import "C"
+
+func FIPSModeSet(mode bool) error {
+ var r C.int
+ if mode {
+ r = C.FIPS_mode_set(1)
+ } else {
+ r = C.FIPS_mode_set(0)
+ }
+ if r != 1 {
+ return errorFromErrorQueue()
+ }
+ return nil
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.c b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.c
new file mode 100644
index 00000000000..9a610292067
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.c
@@ -0,0 +1,367 @@
+/* Go-OpenSSL notice:
+ This file is required for all OpenSSL versions prior to 1.1.0. This simply
+ provides the new 1.1.0 X509_check_* methods for hostname validation if they
+ don't already exist.
+ */
+
+#include <openssl/x509.h>
+
+#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
+
+/* portions from x509v3.h and v3_utl.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* X509 v3 extension utilities */
+
+#include <stdlib.h>
+#include <openssl/ssl.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+
+#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1
+#define X509_CHECK_FLAG_NO_WILDCARDS 0x2
+
+typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len);
+
+/* Compare while ASCII ignoring case. */
+static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ if (pattern_len != subject_len)
+ return 0;
+ while (pattern_len)
+ {
+ unsigned char l = *pattern;
+ unsigned char r = *subject;
+ /* The pattern must not contain NUL characters. */
+ if (l == 0)
+ return 0;
+ if (l != r)
+ {
+ if ('A' <= l && l <= 'Z')
+ l = (l - 'A') + 'a';
+ if ('A' <= r && r <= 'Z')
+ r = (r - 'A') + 'a';
+ if (l != r)
+ return 0;
+ }
+ ++pattern;
+ ++subject;
+ --pattern_len;
+ }
+ return 1;
+ }
+
+/* Compare using memcmp. */
+static int equal_case(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+{
+ /* The pattern must not contain NUL characters. */
+ if (memchr(pattern, '\0', pattern_len) != NULL)
+ return 0;
+ if (pattern_len != subject_len)
+ return 0;
+ return !memcmp(pattern, subject, pattern_len);
+}
+
+/* RFC 5280, section 7.5, requires that only the domain is compared in
+ a case-insensitive manner. */
+static int equal_email(const unsigned char *a, size_t a_len,
+ const unsigned char *b, size_t b_len)
+ {
+ size_t i = a_len;
+ if (a_len != b_len)
+ return 0;
+ /* We search backwards for the '@' character, so that we do
+ not have to deal with quoted local-parts. The domain part
+ is compared in a case-insensitive manner. */
+ while (i > 0)
+ {
+ --i;
+ if (a[i] == '@' || b[i] == '@')
+ {
+ if (!equal_nocase(a + i, a_len - i,
+ b + i, a_len - i))
+ return 0;
+ break;
+ }
+ }
+ if (i == 0)
+ i = a_len;
+ return equal_case(a, i, b, i);
+ }
+
+/* Compare the prefix and suffix with the subject, and check that the
+ characters in-between are valid. */
+static int wildcard_match(const unsigned char *prefix, size_t prefix_len,
+ const unsigned char *suffix, size_t suffix_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ const unsigned char *wildcard_start;
+ const unsigned char *wildcard_end;
+ const unsigned char *p;
+ if (subject_len < prefix_len + suffix_len)
+ return 0;
+ if (!equal_nocase(prefix, prefix_len, subject, prefix_len))
+ return 0;
+ wildcard_start = subject + prefix_len;
+ wildcard_end = subject + (subject_len - suffix_len);
+ if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len))
+ return 0;
+ /* The wildcard must match at least one character. */
+ if (wildcard_start == wildcard_end)
+ return 0;
+ /* Check that the part matched by the wildcard contains only
+ permitted characters and only matches a single label. */
+ for (p = wildcard_start; p != wildcard_end; ++p)
+ if (!(('0' <= *p && *p <= '9') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('a' <= *p && *p <= 'z') ||
+ *p == '-'))
+ return 0;
+ return 1;
+ }
+
+/* Checks if the memory region consistens of [0-9A-Za-z.-]. */
+static int valid_domain_characters(const unsigned char *p, size_t len)
+ {
+ while (len)
+ {
+ if (!(('0' <= *p && *p <= '9') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('a' <= *p && *p <= 'z') ||
+ *p == '-' || *p == '.'))
+ return 0;
+ ++p;
+ --len;
+ }
+ return 1;
+ }
+
+/* Find the '*' in a wildcard pattern. If no such character is found
+ or the pattern is otherwise invalid, returns NULL. */
+static const unsigned char *wildcard_find_star(const unsigned char *pattern,
+ size_t pattern_len)
+ {
+ const unsigned char *star = memchr(pattern, '*', pattern_len);
+ size_t dot_count = 0;
+ const unsigned char *suffix_start;
+ size_t suffix_length;
+ if (star == NULL)
+ return NULL;
+ suffix_start = star + 1;
+ suffix_length = (pattern + pattern_len) - (star + 1);
+ if (!(valid_domain_characters(pattern, star - pattern) &&
+ valid_domain_characters(suffix_start, suffix_length)))
+ return NULL;
+ /* Check that the suffix matches at least two labels. */
+ while (suffix_length)
+ {
+ if (*suffix_start == '.')
+ ++dot_count;
+ ++suffix_start;
+ --suffix_length;
+ }
+ if (dot_count < 2)
+ return NULL;
+ return star;
+ }
+
+/* Compare using wildcards. */
+static int equal_wildcard(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ const unsigned char *star = wildcard_find_star(pattern, pattern_len);
+ if (star == NULL)
+ return equal_nocase(pattern, pattern_len,
+ subject, subject_len);
+ return wildcard_match(pattern, star - pattern,
+ star + 1, (pattern + pattern_len) - star - 1,
+ subject, subject_len);
+ }
+
+/* Compare an ASN1_STRING to a supplied string. If they match
+ * return 1. If cmp_type > 0 only compare if string matches the
+ * type, otherwise convert it to UTF8.
+ */
+
+static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal,
+ const unsigned char *b, size_t blen)
+ {
+ if (!a->data || !a->length)
+ return 0;
+ if (cmp_type > 0)
+ {
+ if (cmp_type != a->type)
+ return 0;
+ if (cmp_type == V_ASN1_IA5STRING)
+ return equal(a->data, a->length, b, blen);
+ if (a->length == (int)blen && !memcmp(a->data, b, blen))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ int astrlen, rv;
+ unsigned char *astr;
+ astrlen = ASN1_STRING_to_UTF8(&astr, a);
+ if (astrlen < 0)
+ return -1;
+ rv = equal(astr, astrlen, b, blen);
+ OPENSSL_free(astr);
+ return rv;
+ }
+ }
+
+static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags, int check_type)
+ {
+ STACK_OF(GENERAL_NAME) *gens = NULL;
+ X509_NAME *name = NULL;
+ int i;
+ int cnid;
+ int alt_type;
+ equal_fn equal;
+ if (check_type == GEN_EMAIL)
+ {
+ cnid = NID_pkcs9_emailAddress;
+ alt_type = V_ASN1_IA5STRING;
+ equal = equal_email;
+ }
+ else if (check_type == GEN_DNS)
+ {
+ cnid = NID_commonName;
+ alt_type = V_ASN1_IA5STRING;
+ if (flags & X509_CHECK_FLAG_NO_WILDCARDS)
+ equal = equal_nocase;
+ else
+ equal = equal_wildcard;
+ }
+ else
+ {
+ cnid = 0;
+ alt_type = V_ASN1_OCTET_STRING;
+ equal = equal_case;
+ }
+
+ if (chklen == 0)
+ chklen = strlen((const char *)chk);
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ if (gens)
+ {
+ int rv = 0;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ GENERAL_NAME *gen;
+ ASN1_STRING *cstr;
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if(gen->type != check_type)
+ continue;
+ if (check_type == GEN_EMAIL)
+ cstr = gen->d.rfc822Name;
+ else if (check_type == GEN_DNS)
+ cstr = gen->d.dNSName;
+ else
+ cstr = gen->d.iPAddress;
+ if (do_check_string(cstr, alt_type, equal, chk, chklen))
+ {
+ rv = 1;
+ break;
+ }
+ }
+ GENERAL_NAMES_free(gens);
+ if (rv)
+ return 1;
+ if (!(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) || !cnid)
+ return 0;
+ }
+ i = -1;
+ name = X509_get_subject_name(x);
+ while((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0)
+ {
+ X509_NAME_ENTRY *ne;
+ ASN1_STRING *str;
+ ne = X509_NAME_get_entry(name, i);
+ str = X509_NAME_ENTRY_get_data(ne);
+ if (do_check_string(str, -1, equal, chk, chklen))
+ return 1;
+ }
+ return 0;
+ }
+
+int _X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_DNS);
+ }
+
+int _X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_EMAIL);
+ }
+
+int _X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_IPADD);
+ }
+
+#endif
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.go
new file mode 100644
index 00000000000..c1d1202fb65
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/hostname.go
@@ -0,0 +1,127 @@
+// 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/ssl.h>
+#include <openssl/conf.h>
+#include <openssl/x509.h>
+
+#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
+#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1
+#define X509_CHECK_FLAG_NO_WILDCARDS 0x2
+
+extern int _X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+extern int _X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+extern int _X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+#endif
+*/
+import "C"
+
+import (
+ "errors"
+ "net"
+ "unsafe"
+)
+
+var (
+ ValidationError = errors.New("Host validation error")
+)
+
+type CheckFlags int
+
+const (
+ AlwaysCheckSubject CheckFlags = C.X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
+ NoWildcards CheckFlags = C.X509_CHECK_FLAG_NO_WILDCARDS
+)
+
+// CheckHost checks that the X509 certificate is signed for the provided
+// host name. See http://www.openssl.org/docs/crypto/X509_check_host.html for
+// more. Note that CheckHost does not check the IP field. See VerifyHostname.
+// Specifically returns ValidationError if the Certificate didn't match but
+// there was no internal error.
+func (c *Certificate) CheckHost(host string, flags CheckFlags) error {
+ chost := unsafe.Pointer(C.CString(host))
+ defer C.free(chost)
+ rv := C._X509_check_host(c.x, (*C.uchar)(chost), C.size_t(len(host)),
+ C.uint(flags))
+ if rv > 0 {
+ return nil
+ }
+ if rv == 0 {
+ return ValidationError
+ }
+ return errors.New("hostname validation had an internal failure")
+}
+
+// CheckEmail checks that the X509 certificate is signed for the provided
+// email address. See http://www.openssl.org/docs/crypto/X509_check_host.html
+// for more.
+// Specifically returns ValidationError if the Certificate didn't match but
+// there was no internal error.
+func (c *Certificate) CheckEmail(email string, flags CheckFlags) error {
+ cemail := unsafe.Pointer(C.CString(email))
+ defer C.free(cemail)
+ rv := C._X509_check_email(c.x, (*C.uchar)(cemail), C.size_t(len(email)),
+ C.uint(flags))
+ if rv > 0 {
+ return nil
+ }
+ if rv == 0 {
+ return ValidationError
+ }
+ return errors.New("email validation had an internal failure")
+}
+
+// CheckIP checks that the X509 certificate is signed for the provided
+// IP address. See http://www.openssl.org/docs/crypto/X509_check_host.html
+// for more.
+// Specifically returns ValidationError if the Certificate didn't match but
+// there was no internal error.
+func (c *Certificate) CheckIP(ip net.IP, flags CheckFlags) error {
+ cip := unsafe.Pointer(&ip[0])
+ rv := C._X509_check_ip(c.x, (*C.uchar)(cip), C.size_t(len(ip)),
+ C.uint(flags))
+ if rv > 0 {
+ return nil
+ }
+ if rv == 0 {
+ return ValidationError
+ }
+ return errors.New("ip validation had an internal failure")
+}
+
+// VerifyHostname is a combination of CheckHost and CheckIP. If the provided
+// hostname looks like an IP address, it will be checked as an IP address,
+// otherwise it will be checked as a hostname.
+// Specifically returns ValidationError if the Certificate didn't match but
+// there was no internal error.
+func (c *Certificate) VerifyHostname(host string) error {
+ var ip net.IP
+ if len(host) >= 3 && host[0] == '[' && host[len(host)-1] == ']' {
+ ip = net.ParseIP(host[1 : len(host)-1])
+ } else {
+ ip = net.ParseIP(host)
+ }
+ if ip != nil {
+ return c.CheckIP(ip, 0)
+ }
+ return c.CheckHost(host, 0)
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/http.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/http.go
new file mode 100644
index 00000000000..e3be32c264a
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/http.go
@@ -0,0 +1,61 @@
+// 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 (
+ "net/http"
+)
+
+// ListenAndServeTLS will take an http.Handler and serve it using OpenSSL over
+// the given tcp address, configured to use the provided cert and key files.
+func ListenAndServeTLS(addr string, cert_file string, key_file string,
+ handler http.Handler) error {
+ return ServerListenAndServeTLS(
+ &http.Server{Addr: addr, Handler: handler}, cert_file, key_file)
+}
+
+// ServerListenAndServeTLS will take an http.Server and serve it using OpenSSL
+// configured to use the provided cert and key files.
+func ServerListenAndServeTLS(srv *http.Server,
+ cert_file, key_file string) error {
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":https"
+ }
+
+ ctx, err := NewCtxFromFiles(cert_file, key_file)
+ if err != nil {
+ return err
+ }
+
+ l, err := Listen("tcp", addr, ctx)
+ if err != nil {
+ return err
+ }
+
+ return srv.Serve(l)
+}
+
+// TODO: http client integration
+// holy crap, getting this integrated nicely with the Go stdlib HTTP client
+// stack so that it does proxying, connection pooling, and most importantly
+// hostname verification is really hard. So much stuff is hardcoded to just use
+// the built-in TLS lib. I think to get this to work either some crazy
+// hacktackery beyond me, an almost straight up fork of the HTTP client, or
+// serious stdlib internal refactoring is necessary.
+// even more so, good luck getting openssl to use the operating system default
+// root certificates if the user doesn't provide any. sadlol
+// NOTE: if you're going to try and write your own round tripper, at least use
+// openssl.Dial, or equivalent logic
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init.go
new file mode 100644
index 00000000000..7663a480ed2
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init.go
@@ -0,0 +1,155 @@
+// 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 is a light wrapper around OpenSSL for Go.
+
+It strives to provide a near-drop-in replacement for the Go standard library
+tls package, while allowing for:
+
+Performance
+
+OpenSSL is battle-tested and optimized C. While Go's built-in library shows
+great promise, it is still young and in some places, inefficient. This simple
+OpenSSL wrapper can often do at least 2x with the same cipher and protocol.
+
+On my lappytop, I get the following benchmarking speeds:
+ BenchmarkSHA1Large_openssl 1000 2611282 ns/op 401.56 MB/s
+ BenchmarkSHA1Large_stdlib 500 3963983 ns/op 264.53 MB/s
+ BenchmarkSHA1Small_openssl 1000000 3476 ns/op 0.29 MB/s
+ BenchmarkSHA1Small_stdlib 5000000 550 ns/op 1.82 MB/s
+ BenchmarkSHA256Large_openssl 200 8085314 ns/op 129.69 MB/s
+ BenchmarkSHA256Large_stdlib 100 18948189 ns/op 55.34 MB/s
+ BenchmarkSHA256Small_openssl 1000000 4262 ns/op 0.23 MB/s
+ BenchmarkSHA256Small_stdlib 1000000 1444 ns/op 0.69 MB/s
+ BenchmarkOpenSSLThroughput 100000 21634 ns/op 47.33 MB/s
+ BenchmarkStdlibThroughput 50000 58974 ns/op 17.36 MB/s
+
+Interoperability
+
+Many systems support OpenSSL with a variety of plugins and modules for things,
+such as hardware acceleration in embedded devices.
+
+Greater flexibility and configuration
+
+OpenSSL allows for far greater configuration of corner cases and backwards
+compatibility (such as support of SSLv2). You shouldn't be using SSLv2 if you
+can help but, but sometimes you can't help it.
+
+Security
+
+Yeah yeah, Heartbleed. But according to the author of the standard library's
+TLS implementation, Go's TLS library is vulnerable to timing attacks. And
+whether or not OpenSSL received the appropriate amount of scrutiny
+pre-Heartbleed, it sure is receiving it now.
+
+Usage
+
+Starting an HTTP server that uses OpenSSL is very easy. It's as simple as:
+ log.Fatal(openssl.ListenAndServeTLS(
+ ":8443", "my_server.crt", "my_server.key", myHandler))
+
+Getting a net.Listener that uses OpenSSL is also easy:
+ ctx, err := openssl.NewCtxFromFiles("my_server.crt", "my_server.key")
+ if err != nil {
+ log.Fatal(err)
+ }
+ l, err := openssl.Listen("tcp", ":7777", ctx)
+
+Making a client connection is straightforward too:
+ ctx, err := NewCtx()
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = ctx.LoadVerifyLocations("/etc/ssl/certs/ca-certificates.crt", "")
+ if err != nil {
+ log.Fatal(err)
+ }
+ conn, err := openssl.Dial("tcp", "localhost:7777", ctx, 0)
+
+Help wanted: To get this library to work with net/http's client, we
+had to fork net/http. It would be nice if an alternate http client library
+supported the generality needed to use OpenSSL instead of crypto/tls.
+*/
+package openssl
+
+/*
+#include <openssl/ssl.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+
+extern int Goopenssl_init_locks();
+extern void Goopenssl_thread_locking_callback(int, int, const char*, int);
+
+static int Goopenssl_init_threadsafety() {
+ // Set up OPENSSL thread safety callbacks. We only set the locking
+ // callback because the default id callback implementation is good
+ // enough for us.
+ int rc = Goopenssl_init_locks();
+ if (rc == 0) {
+ CRYPTO_set_locking_callback(Goopenssl_thread_locking_callback);
+ }
+ return rc;
+}
+
+static void OpenSSL_add_all_algorithms_not_a_macro() {
+ OpenSSL_add_all_algorithms();
+}
+
+*/
+import "C"
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "sync"
+)
+
+var (
+ sslMutexes []sync.Mutex
+)
+
+func init() {
+ C.OPENSSL_config(nil)
+ C.ENGINE_load_builtin_engines()
+ C.SSL_load_error_strings()
+ C.SSL_library_init()
+ C.OpenSSL_add_all_algorithms_not_a_macro()
+ rc := C.Goopenssl_init_threadsafety()
+ if rc != 0 {
+ panic(fmt.Errorf("Goopenssl_init_locks failed with %d", rc))
+ }
+}
+
+// errorFromErrorQueue needs to run in the same OS thread as the operation
+// that caused the possible error
+func errorFromErrorQueue() error {
+ var errs []string
+ for {
+ err := C.ERR_get_error()
+ if err == 0 {
+ break
+ }
+ errs = append(errs, fmt.Sprintf("%s:%s:%s",
+ C.GoString(C.ERR_lib_error_string(err)),
+ C.GoString(C.ERR_func_error_string(err)),
+ C.GoString(C.ERR_reason_error_string(err))))
+ }
+ return errors.New(fmt.Sprintf("SSL errors: %s", strings.Join(errs, "\n")))
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_posix.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_posix.go
new file mode 100644
index 00000000000..03ed0f01bd0
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_posix.go
@@ -0,0 +1,64 @@
+// 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 linux darwin cgo
+// +build !windows
+
+package openssl
+
+/*
+#include <errno.h>
+#include <openssl/crypto.h>
+#include <pthread.h>
+
+pthread_mutex_t* goopenssl_locks;
+
+int Goopenssl_init_locks() {
+ int rc = 0;
+ int nlock;
+ int i;
+ int locks_needed = CRYPTO_num_locks();
+
+ goopenssl_locks = (pthread_mutex_t*)malloc(
+ sizeof(pthread_mutex_t) * locks_needed);
+ if (!goopenssl_locks) {
+ return ENOMEM;
+ }
+ for (nlock = 0; nlock < locks_needed; ++nlock) {
+ rc = pthread_mutex_init(&goopenssl_locks[nlock], NULL);
+ if (rc != 0) {
+ break;
+ }
+ }
+
+ if (rc != 0) {
+ for (i = nlock - 1; i >= 0; --i) {
+ pthread_mutex_destroy(&goopenssl_locks[i]);
+ }
+ free(goopenssl_locks);
+ goopenssl_locks = NULL;
+ }
+ return rc;
+}
+
+void Goopenssl_thread_locking_callback(int mode, int n, const char *file,
+ int line) {
+ if (mode & CRYPTO_LOCK) {
+ pthread_mutex_lock(&goopenssl_locks[n]);
+ } else {
+ pthread_mutex_unlock(&goopenssl_locks[n]);
+ }
+}
+*/
+import "C"
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_windows.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_windows.go
new file mode 100644
index 00000000000..5eca9fa0eac
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/init_windows.go
@@ -0,0 +1,60 @@
+// 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 windows cgo
+
+package openssl
+
+/*
+
+#cgo windows LDFLAGS: -lssleay32 -llibeay32 -L c:/openssl/bin
+#cgo windows CFLAGS: -I"c:/openssl/include"
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <errno.h>
+#include <openssl/crypto.h>
+#include <windows.h>
+
+CRITICAL_SECTION* goopenssl_locks;
+
+int Goopenssl_init_locks() {
+ int rc = 0;
+ int nlock;
+ int i;
+ int locks_needed = CRYPTO_num_locks();
+
+ goopenssl_locks = (CRITICAL_SECTION*)malloc(
+ sizeof(*goopenssl_locks) * locks_needed);
+ if (!goopenssl_locks) {
+ return ENOMEM;
+ }
+ for (nlock = 0; nlock < locks_needed; ++nlock) {
+ InitializeCriticalSection(&goopenssl_locks[nlock]);
+ }
+
+ return 0;
+}
+
+void Goopenssl_thread_locking_callback(int mode, int n, const char *file,
+ int line) {
+ if (mode & CRYPTO_LOCK) {
+ EnterCriticalSection(&goopenssl_locks[n]);
+ } else {
+ LeaveCriticalSection(&goopenssl_locks[n]);
+ }
+}
+*/
+import "C"
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key.go
new file mode 100644
index 00000000000..c69a101631f
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key_test.go
new file mode 100644
index 00000000000..54752d381bf
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/key_test.go
@@ -0,0 +1,149 @@
+// 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 (
+ "bytes"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/hex"
+ pem_pkg "encoding/pem"
+ "io/ioutil"
+ "testing"
+)
+
+func TestMarshal(t *testing.T) {
+ key, err := LoadPrivateKeyFromPEM(keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := LoadCertificateFromPEM(certBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pem, err := cert.MarshalPEM()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(pem, certBytes) {
+ ioutil.WriteFile("generated", pem, 0644)
+ ioutil.WriteFile("hardcoded", certBytes, 0644)
+ t.Fatal("invalid cert pem bytes")
+ }
+
+ pem, err = key.MarshalPKCS1PrivateKeyPEM()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(pem, keyBytes) {
+ ioutil.WriteFile("generated", pem, 0644)
+ ioutil.WriteFile("hardcoded", keyBytes, 0644)
+ t.Fatal("invalid private key pem bytes")
+ }
+ tls_cert, err := tls.X509KeyPair(certBytes, keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tls_key, ok := tls_cert.PrivateKey.(*rsa.PrivateKey)
+ if !ok {
+ t.Fatal("FASDFASDF")
+ }
+ _ = tls_key
+
+ der, err := key.MarshalPKCS1PrivateKeyDER()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tls_der := x509.MarshalPKCS1PrivateKey(tls_key)
+ if !bytes.Equal(der, tls_der) {
+ t.Fatal("invalid private key der bytes: %s\n v.s. %s\n",
+ hex.Dump(der), hex.Dump(tls_der))
+ }
+
+ der, err = key.MarshalPKIXPublicKeyDER()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tls_der, err = x509.MarshalPKIXPublicKey(&tls_key.PublicKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(der, tls_der) {
+ ioutil.WriteFile("generated", []byte(hex.Dump(der)), 0644)
+ ioutil.WriteFile("hardcoded", []byte(hex.Dump(tls_der)), 0644)
+ t.Fatal("invalid public key der bytes")
+ }
+
+ pem, err = key.MarshalPKIXPublicKeyPEM()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tls_pem := pem_pkg.EncodeToMemory(&pem_pkg.Block{
+ Type: "PUBLIC KEY", Bytes: tls_der})
+ if !bytes.Equal(pem, tls_pem) {
+ ioutil.WriteFile("generated", pem, 0644)
+ ioutil.WriteFile("hardcoded", tls_pem, 0644)
+ t.Fatal("invalid public key pem bytes")
+ }
+
+ loaded_pubkey_from_pem, err := LoadPublicKeyFromPEM(pem)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ loaded_pubkey_from_der, err := LoadPublicKeyFromDER(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ new_der_from_pem, err := loaded_pubkey_from_pem.MarshalPKIXPublicKeyDER()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ new_der_from_der, err := loaded_pubkey_from_der.MarshalPKIXPublicKeyDER()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(new_der_from_der, tls_der) {
+ ioutil.WriteFile("generated", []byte(hex.Dump(new_der_from_der)), 0644)
+ ioutil.WriteFile("hardcoded", []byte(hex.Dump(tls_der)), 0644)
+ t.Fatal("invalid public key der bytes")
+ }
+
+ if !bytes.Equal(new_der_from_pem, tls_der) {
+ ioutil.WriteFile("generated", []byte(hex.Dump(new_der_from_pem)), 0644)
+ ioutil.WriteFile("hardcoded", []byte(hex.Dump(tls_der)), 0644)
+ 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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/net.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/net.go
new file mode 100644
index 00000000000..3cdd040d4d4
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/net.go
@@ -0,0 +1,134 @@
+// 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 (
+ "errors"
+ "net"
+)
+
+type listener struct {
+ net.Listener
+ ctx *Ctx
+}
+
+func (l *listener) Accept() (c net.Conn, err error) {
+ c, err = l.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ ssl_c, err := Server(c, l.ctx)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ return ssl_c, nil
+}
+
+// NewListener wraps an existing net.Listener such that all accepted
+// connections are wrapped as OpenSSL server connections using the provided
+// context ctx.
+func NewListener(inner net.Listener, ctx *Ctx) net.Listener {
+ return &listener{
+ Listener: inner,
+ ctx: ctx}
+}
+
+// Listen is a wrapper around net.Listen that wraps incoming connections with
+// an OpenSSL server connection using the provided context ctx.
+func Listen(network, laddr string, ctx *Ctx) (net.Listener, error) {
+ if ctx == nil {
+ return nil, errors.New("no ssl context provided")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, ctx), nil
+}
+
+type DialFlags int
+
+const (
+ InsecureSkipHostVerification DialFlags = 1 << iota
+ DisableSNI
+)
+
+// Dial 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.
+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
+ }
+ if ctx == nil {
+ var err error
+ ctx, err = NewCtx()
+ if err != nil {
+ return nil, err
+ }
+ // TODO: use operating system default certificate chain?
+ }
+ c, err := net.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ conn, err := Client(c, ctx)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ // XXX removed SNI
+ err = conn.Handshake()
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ if flags&InsecureSkipHostVerification == 0 {
+ err = conn.VerifyHostname(host)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+ }
+ return conn, nil
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/nid.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/nid.go
new file mode 100644
index 00000000000..c80f237b605
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/oracle_stubs.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/oracle_stubs.go
new file mode 100644
index 00000000000..30492f3b9d8
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/oracle_stubs.go
@@ -0,0 +1,162 @@
+// 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
+
+import (
+ "errors"
+ "net"
+ "time"
+)
+
+const (
+ SSLRecordSize = 16 * 1024
+)
+
+type Conn struct{}
+
+func Client(conn net.Conn, ctx *Ctx) (*Conn, error)
+func Server(conn net.Conn, ctx *Ctx) (*Conn, error)
+
+func (c *Conn) Handshake() error
+func (c *Conn) PeerCertificate() (*Certificate, error)
+func (c *Conn) Close() error
+func (c *Conn) Read(b []byte) (n int, err error)
+func (c *Conn) Write(b []byte) (written int, err error)
+
+func (c *Conn) VerifyHostname(host string) error
+
+func (c *Conn) LocalAddr() net.Addr
+func (c *Conn) RemoteAddr() net.Addr
+func (c *Conn) SetDeadline(t time.Time) error
+func (c *Conn) SetReadDeadline(t time.Time) error
+func (c *Conn) SetWriteDeadline(t time.Time) error
+
+type Ctx struct{}
+
+type SSLVersion int
+
+const (
+ SSLv3 SSLVersion = 0x02
+ TLSv1 SSLVersion = 0x03
+ TLSv1_1 SSLVersion = 0x04
+ TLSv1_2 SSLVersion = 0x05
+ AnyVersion SSLVersion = 0x06
+)
+
+func NewCtxWithVersion(version SSLVersion) (*Ctx, error)
+func NewCtx() (*Ctx, error)
+func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error)
+func (c *Ctx) UseCertificate(cert *Certificate) error
+func (c *Ctx) UsePrivateKey(key PrivateKey) error
+
+type CertificateStore struct{}
+
+func (c *Ctx) GetCertificateStore() *CertificateStore
+
+func (s *CertificateStore) AddCertificate(cert *Certificate) error
+
+func (c *Ctx) LoadVerifyLocations(ca_file string, ca_path string) error
+
+type Options int
+
+const (
+ NoCompression Options = 0
+ NoSSLv2 Options = 0
+ NoSSLv3 Options = 0
+ NoTLSv1 Options = 0
+ CipherServerPreference Options = 0
+ NoSessionResumptionOrRenegotiation Options = 0
+ NoTicket Options = 0
+)
+
+func (c *Ctx) SetOptions(options Options) Options
+
+type Modes int
+
+const (
+ ReleaseBuffers Modes = 0
+)
+
+func (c *Ctx) SetMode(modes Modes) Modes
+
+type VerifyOptions int
+
+const (
+ VerifyNone VerifyOptions = 0
+ VerifyPeer VerifyOptions = 0
+ VerifyFailIfNoPeerCert VerifyOptions = 0
+ VerifyClientOnce VerifyOptions = 0
+)
+
+func (c *Ctx) SetVerify(options VerifyOptions)
+func (c *Ctx) SetVerifyDepth(depth int)
+func (c *Ctx) SetSessionId(session_id []byte) error
+
+func (c *Ctx) SetCipherList(list string) error
+
+type SessionCacheModes int
+
+const (
+ SessionCacheOff SessionCacheModes = 0
+ SessionCacheClient SessionCacheModes = 0
+ SessionCacheServer SessionCacheModes = 0
+ SessionCacheBoth SessionCacheModes = 0
+ NoAutoClear SessionCacheModes = 0
+ NoInternalLookup SessionCacheModes = 0
+ NoInternalStore SessionCacheModes = 0
+ NoInternal SessionCacheModes = 0
+)
+
+func (c *Ctx) SetSessionCacheMode(modes SessionCacheModes) SessionCacheModes
+
+var (
+ ValidationError = errors.New("Host validation error")
+)
+
+type CheckFlags int
+
+const (
+ AlwaysCheckSubject CheckFlags = 0
+ NoWildcards CheckFlags = 0
+)
+
+func (c *Certificate) CheckHost(host string, flags CheckFlags) error
+func (c *Certificate) CheckEmail(email string, flags CheckFlags) error
+func (c *Certificate) CheckIP(ip net.IP, flags CheckFlags) error
+func (c *Certificate) VerifyHostname(host string) error
+
+type PublicKey interface {
+ MarshalPKIXPublicKeyPEM() (pem_block []byte, err error)
+ MarshalPKIXPublicKeyDER() (der_block []byte, err error)
+ evpPKey() struct{}
+}
+
+type PrivateKey interface {
+ PublicKey
+ MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error)
+ MarshalPKCS1PrivateKeyDER() (der_block []byte, err error)
+}
+
+func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error)
+
+type Certificate struct{}
+
+func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error)
+
+func (c *Certificate) MarshalPEM() (pem_block []byte, err error)
+
+func (c *Certificate) PublicKey() (PublicKey, error)
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/password.c b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/password.c
new file mode 100644
index 00000000000..db9582ca726
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/password.c
@@ -0,0 +1,10 @@
+#include <openssl/ssl.h>
+#include "_cgo_export.h"
+
+int password_cb(char *buf,int buf_len, int rwflag,void *userdata) {
+ char* pw = (char *)userdata;
+ int l = strlen(pw);
+ if (l + 1 > buf_len) return 0;
+ strcpy(buf,pw);
+ return l;
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/pem.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/pem.go
new file mode 100644
index 00000000000..6dad5972dbd
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/pem.go
@@ -0,0 +1,32 @@
+// 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 (
+ "regexp"
+)
+
+var pemSplit *regexp.Regexp = regexp.MustCompile(`(?sm)` +
+ `(^-----[\s-]*?BEGIN.*?-----$` +
+ `.*?` +
+ `^-----[\s-]*?END.*?-----$)`)
+
+func SplitPEM(data []byte) [][]byte {
+ var results [][]byte
+ for _, block := range pemSplit.FindAll(data, -1) {
+ results = append(results, block)
+ }
+ return results
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1.go
new file mode 100644
index 00000000000..2592b6627d1
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1.go
@@ -0,0 +1,99 @@
+// 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "openssl/evp.h"
+*/
+import "C"
+
+import (
+ "errors"
+ "runtime"
+ "unsafe"
+)
+
+type SHA1Hash struct {
+ ctx C.EVP_MD_CTX
+ engine *Engine
+}
+
+func NewSHA1Hash() (*SHA1Hash, error) { return NewSHA1HashWithEngine(nil) }
+
+func NewSHA1HashWithEngine(e *Engine) (*SHA1Hash, error) {
+ hash := &SHA1Hash{engine: e}
+ C.EVP_MD_CTX_init(&hash.ctx)
+ runtime.SetFinalizer(hash, func(hash *SHA1Hash) { hash.Close() })
+ if err := hash.Reset(); err != nil {
+ return nil, err
+ }
+ return hash, nil
+}
+
+func (s *SHA1Hash) Close() {
+ C.EVP_MD_CTX_cleanup(&s.ctx)
+}
+
+func engineRef(e *Engine) *C.ENGINE {
+ if e == nil {
+ return nil
+ }
+ return e.e
+}
+
+func (s *SHA1Hash) Reset() error {
+ if 1 != C.EVP_DigestInit_ex(&s.ctx, C.EVP_sha1(), engineRef(s.engine)) {
+ return errors.New("openssl: sha1: cannot init digest ctx")
+ }
+ return nil
+}
+
+func (s *SHA1Hash) Write(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if 1 != C.EVP_DigestUpdate(&s.ctx, unsafe.Pointer(&p[0]),
+ C.size_t(len(p))) {
+ return 0, errors.New("openssl: sha1: cannot update digest")
+ }
+ return len(p), nil
+}
+
+func (s *SHA1Hash) Sum() (result [20]byte, err error) {
+ if 1 != C.EVP_DigestFinal_ex(&s.ctx,
+ (*C.uchar)(unsafe.Pointer(&result[0])), nil) {
+ return result, errors.New("openssl: sha1: cannot finalize ctx")
+ }
+ return result, s.Reset()
+}
+
+func SHA1(data []byte) (result [20]byte, err error) {
+ hash, err := NewSHA1Hash()
+ if err != nil {
+ return result, err
+ }
+ defer hash.Close()
+ if _, err := hash.Write(data); err != nil {
+ return result, err
+ }
+ return hash.Sum()
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1_test.go
new file mode 100644
index 00000000000..37037e4468b
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha1_test.go
@@ -0,0 +1,111 @@
+// 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
+
+import (
+ "crypto/rand"
+ "crypto/sha1"
+ "io"
+ "testing"
+)
+
+func TestSHA1(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ buf := make([]byte, 10*1024-i)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ t.Fatal(err)
+ }
+
+ expected := sha1.Sum(buf)
+ got, err := SHA1(buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if expected != got {
+ t.Fatal("exp:%x got:%x", expected, got)
+ }
+ }
+}
+
+func TestSHA1Writer(t *testing.T) {
+ ohash, err := NewSHA1Hash()
+ if err != nil {
+ t.Fatal(err)
+ }
+ hash := sha1.New()
+
+ for i := 0; i < 100; i++ {
+ if err := ohash.Reset(); err != nil {
+ t.Fatal(err)
+ }
+ hash.Reset()
+ buf := make([]byte, 10*1024-i)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := ohash.Write(buf); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := hash.Write(buf); err != nil {
+ t.Fatal(err)
+ }
+
+ var got, exp [20]byte
+
+ hash.Sum(exp[:0])
+ got, err := ohash.Sum()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if got != exp {
+ t.Fatal("exp:%x got:%x", exp, got)
+ }
+ }
+}
+
+type shafunc func([]byte)
+
+func benchmarkSHA1(b *testing.B, length int64, fn shafunc) {
+ buf := make([]byte, length)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(length)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ fn(buf)
+ }
+}
+
+func BenchmarkSHA1Large_openssl(b *testing.B) {
+ benchmarkSHA1(b, 1024*1024, func(buf []byte) { SHA1(buf) })
+}
+
+func BenchmarkSHA1Large_stdlib(b *testing.B) {
+ benchmarkSHA1(b, 1024*1024, func(buf []byte) { sha1.Sum(buf) })
+}
+
+func BenchmarkSHA1Small_openssl(b *testing.B) {
+ benchmarkSHA1(b, 1, func(buf []byte) { SHA1(buf) })
+}
+
+func BenchmarkSHA1Small_stdlib(b *testing.B) {
+ benchmarkSHA1(b, 1, func(buf []byte) { sha1.Sum(buf) })
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256.go
new file mode 100644
index 00000000000..6785b32f881
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256.go
@@ -0,0 +1,92 @@
+// 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "openssl/evp.h"
+*/
+import "C"
+
+import (
+ "errors"
+ "runtime"
+ "unsafe"
+)
+
+type SHA256Hash struct {
+ ctx C.EVP_MD_CTX
+ engine *Engine
+}
+
+func NewSHA256Hash() (*SHA256Hash, error) { return NewSHA256HashWithEngine(nil) }
+
+func NewSHA256HashWithEngine(e *Engine) (*SHA256Hash, error) {
+ hash := &SHA256Hash{engine: e}
+ C.EVP_MD_CTX_init(&hash.ctx)
+ runtime.SetFinalizer(hash, func(hash *SHA256Hash) { hash.Close() })
+ if err := hash.Reset(); err != nil {
+ return nil, err
+ }
+ return hash, nil
+}
+
+func (s *SHA256Hash) Close() {
+ C.EVP_MD_CTX_cleanup(&s.ctx)
+}
+
+func (s *SHA256Hash) Reset() error {
+ if 1 != C.EVP_DigestInit_ex(&s.ctx, C.EVP_sha256(), engineRef(s.engine)) {
+ return errors.New("openssl: sha256: cannot init digest ctx")
+ }
+ return nil
+}
+
+func (s *SHA256Hash) Write(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if 1 != C.EVP_DigestUpdate(&s.ctx, unsafe.Pointer(&p[0]),
+ C.size_t(len(p))) {
+ return 0, errors.New("openssl: sha256: cannot update digest")
+ }
+ return len(p), nil
+}
+
+func (s *SHA256Hash) Sum() (result [32]byte, err error) {
+ if 1 != C.EVP_DigestFinal_ex(&s.ctx,
+ (*C.uchar)(unsafe.Pointer(&result[0])), nil) {
+ return result, errors.New("openssl: sha256: cannot finalize ctx")
+ }
+ return result, s.Reset()
+}
+
+func SHA256(data []byte) (result [32]byte, err error) {
+ hash, err := NewSHA256Hash()
+ if err != nil {
+ return result, err
+ }
+ defer hash.Close()
+ if _, err := hash.Write(data); err != nil {
+ return result, err
+ }
+ return hash.Sum()
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256_test.go
new file mode 100644
index 00000000000..89df88afd44
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sha256_test.go
@@ -0,0 +1,109 @@
+// 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
+
+import (
+ "crypto/rand"
+ "crypto/sha256"
+ "io"
+ "testing"
+)
+
+func TestSHA256(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ buf := make([]byte, 10*1024-i)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ t.Fatal(err)
+ }
+
+ expected := sha256.Sum256(buf)
+ got, err := SHA256(buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if expected != got {
+ t.Fatal("exp:%x got:%x", expected, got)
+ }
+ }
+}
+
+func TestSHA256Writer(t *testing.T) {
+ ohash, err := NewSHA256Hash()
+ if err != nil {
+ t.Fatal(err)
+ }
+ hash := sha256.New()
+
+ for i := 0; i < 100; i++ {
+ if err := ohash.Reset(); err != nil {
+ t.Fatal(err)
+ }
+ hash.Reset()
+ buf := make([]byte, 10*1024-i)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := ohash.Write(buf); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := hash.Write(buf); err != nil {
+ t.Fatal(err)
+ }
+
+ var got, exp [32]byte
+
+ hash.Sum(exp[:0])
+ got, err := ohash.Sum()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if got != exp {
+ t.Fatal("exp:%x got:%x", exp, got)
+ }
+ }
+}
+
+func benchmarkSHA256(b *testing.B, length int64, fn shafunc) {
+ buf := make([]byte, length)
+ if _, err := io.ReadFull(rand.Reader, buf); err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(length)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ fn(buf)
+ }
+}
+
+func BenchmarkSHA256Large_openssl(b *testing.B) {
+ benchmarkSHA256(b, 1024*1024, func(buf []byte) { SHA256(buf) })
+}
+
+func BenchmarkSHA256Large_stdlib(b *testing.B) {
+ benchmarkSHA256(b, 1024*1024, func(buf []byte) { sha256.Sum256(buf) })
+}
+
+func BenchmarkSHA256Small_openssl(b *testing.B) {
+ benchmarkSHA256(b, 1, func(buf []byte) { SHA256(buf) })
+}
+
+func BenchmarkSHA256Small_stdlib(b *testing.B) {
+ benchmarkSHA256(b, 1, func(buf []byte) { sha256.Sum256(buf) })
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni.c b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni.c
new file mode 100644
index 00000000000..5398da869b8
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/sni_test.go
new file mode 100644
index 00000000000..ee3b1a8bbaf
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl.go
new file mode 100644
index 00000000000..d6120e15d99
--- /dev/null
+++ b/src/mongo/gotools/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/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl_test.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl_test.go
new file mode 100644
index 00000000000..f83225dec97
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/ssl_test.go
@@ -0,0 +1,633 @@
+// 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 (
+ "bytes"
+ "crypto/rand"
+ "crypto/tls"
+ "io"
+ "io/ioutil"
+ "net"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/spacemonkeygo/openssl/utils"
+)
+
+var (
+ certBytes = []byte(`-----BEGIN CERTIFICATE-----
+MIIDxDCCAqygAwIBAgIVAMcK/0VWQr2O3MNfJCydqR7oVELcMA0GCSqGSIb3DQEB
+BQUAMIGQMUkwRwYDVQQDE0A1NjdjZGRmYzRjOWZiNTYwZTk1M2ZlZjA1N2M0NGFm
+MDdiYjc4MDIzODIxYTA5NThiY2RmMGMwNzJhOTdiMThhMQswCQYDVQQGEwJVUzEN
+MAsGA1UECBMEVXRhaDEQMA4GA1UEBxMHTWlkdmFsZTEVMBMGA1UEChMMU3BhY2Ug
+TW9ua2V5MB4XDTEzMTIxNzE4MzgyMloXDTIzMTIxNTE4MzgyMlowgZAxSTBHBgNV
+BAMTQDM4NTg3ODRkMjU1NTdiNTM1MWZmNjRmMmQzMTQ1ZjkwYTJlMTIzMDM4Y2Yz
+Mjc1Yzg1OTM1MjcxYWIzMmNiMDkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFo
+MRAwDgYDVQQHEwdNaWR2YWxlMRUwEwYDVQQKEwxTcGFjZSBNb25rZXkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdf3icNvFsrlrnNLi8SocscqlSbFq+
+pEvmhcSoqgDLqebnqu8Ld73HJJ74MGXEgRX8xZT5FinOML31CR6t9E/j3dqV6p+G
+fdlFLe3IqtC0/bPVnCDBirBygBI4uCrMq+1VhAxPWclrDo7l9QRYbsExH9lfn+Ry
+vxeNMZiOASasvVZNncY8E9usBGRdH17EfDL/TPwXqWOLyxSN5o54GTztjjy9w9CG
+QP7jcCueKYyQJQCtEmnwc6P/q6/EPv5R6drBkX6loAPtmCUAkHqxkWOJrRq/v7Pw
+zRYhfY+ZpVHGc7WEkDnLzRiUypr1C9oxvLKS10etZEIwEdKyOkSg2fdPAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEcz0RTTJ99l
+HTK/zTyfV5VZEhtwqu6bwre/hD7lhI+1ji0DZYGIgCbJLKuZhj+cHn2h5nPhN7zE
+M9tc4pn0TgeVS0SVFSe6TGnIFipNogvP17E+vXpDZcW/xn9kPKeVCZc1hlDt1W4Z
+5q+ub3aUwuMwYs7bcArtDrumCmciJ3LFyNhebPi4mntb5ooeLFLaujEmVYyrQnpo
+tWKC9sMlJmLm4yAso64Sv9KLS2T9ivJBNn0ZtougozBCCTqrqgZVjha+B2yjHe9f
+sRkg/uxcJf7wC5Y0BLlp1+aPwdmZD87T3a1uQ1Ij93jmHG+2T9U20MklHAePOl0q
+yTqdSPnSH1c=
+-----END CERTIFICATE-----
+`)
+ keyBytes = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA3X94nDbxbK5a5zS4vEqHLHKpUmxavqRL5oXEqKoAy6nm56rv
+C3e9xySe+DBlxIEV/MWU+RYpzjC99QkerfRP493aleqfhn3ZRS3tyKrQtP2z1Zwg
+wYqwcoASOLgqzKvtVYQMT1nJaw6O5fUEWG7BMR/ZX5/kcr8XjTGYjgEmrL1WTZ3G
+PBPbrARkXR9exHwy/0z8F6lji8sUjeaOeBk87Y48vcPQhkD+43ArnimMkCUArRJp
+8HOj/6uvxD7+UenawZF+paAD7ZglAJB6sZFjia0av7+z8M0WIX2PmaVRxnO1hJA5
+y80YlMqa9QvaMbyyktdHrWRCMBHSsjpEoNn3TwIDAQABAoIBAQCwgp6YzmgCFce3
+LBpzYmjqEM3CMzr1ZXRe1gbr6d4Mbu7leyBX4SpJAnP0kIzo1X2yG7ol7XWPLOST
+2pqqQWFQ00EX6wsJYEy+hmVRXl5HfU3MUkkAMwd9l3Xt4UWqKPBPD5XHvmN2fvl9
+Y4388vXdseXGAGNK1eFs0TMjJuOtDxDyrmJcnxpJ7y/77y/Hb5rUa9DCvj8tkKHg
+HmeIwQE0HhIFofj+qCYbqeVyjbPAaYZMrISXb2HmcyULKEOGRbMH24IzInKA0NxV
+kdP9qmV8Y2bJ609Fft/y8Vpj31iEdq/OFXyobdVvnXMnaVyAetoaWy7AOTIQ2Cnw
+wGbJ/F8BAoGBAN/pCnLQrWREeVMuFjf+MgYgCtRRaQ8EOVvjYcXXi0PhtOMFTAb7
+djqhlgmBOFsmeXcb8YRZsF+pNtu1xk5RJOquyKfK8j1rUdAJfoxGHiaUFI2/1i9E
+zuXX/Ao0xNRkWMxMKuwYBmmt1fMuVo+1M8UEwFMdHRtgxe+/+eOV1J2PAoGBAP09
+7GLOYSYAI1OO3BN/bEVNau6tAxP5YShGmX2Qxy0+ooxHZ1V3D8yo6C0hSg+H+fPT
+mjMgGcvaW6K+QyCdHDjgbk2hfdZ+Beq92JApPrH9gMV7MPhwHzgwjzDDio9OFxYY
+3vjBQ2yX+9jvz9lkvq2NM3fqFqbsG6Et+5mCc6pBAoGBAI62bxVtEgbladrtdfXs
+S6ABzkUzOl362EBL9iZuUnJKqstDtgiBQALwuLuIJA5cwHB9W/t6WuMt7CwveJy0
+NW5rRrNDtBAXlgad9o2bp135ZfxO+EoadjCi8B7lMUsaRkq4hWcDjRrQVJxxvXRN
+DxkVBSw0Uzf+/0nnN3OqLODbAoGACCY+/isAC1YDzQOS53m5RT2pjEa7C6CB1Ob4
+t4a6MiWK25LMq35qXr6swg8JMBjDHWqY0r5ctievvTv8Mwd7SgVG526j+wwRKq2z
+U2hQYS/0Peap+8S37Hn7kakpQ1VS/t4MBttJTSxS6XdGLAvG6xTZLCm3UuXUOcqe
+ByGgkUECgYEAmop45kRi974g4MPvyLplcE4syb19ifrHj76gPRBi94Cp8jZosY1T
+ucCCa4lOGgPtXJ0Qf1c8yq5vh4yqkQjrgUTkr+CFDGR6y4CxmNDQxEMYIajaIiSY
+qmgvgyRayemfO2zR0CPgC6wSoGBth+xW6g+WA8y0z76ZSaWpFi8lVM4=
+-----END RSA PRIVATE KEY-----
+`)
+)
+
+func NetPipe(t testing.TB) (net.Conn, net.Conn) {
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer l.Close()
+ client_future := utils.NewFuture()
+ go func() {
+ client_future.Set(net.Dial(l.Addr().Network(), l.Addr().String()))
+ }()
+ var errs utils.ErrorGroup
+ server_conn, err := l.Accept()
+ errs.Add(err)
+ client_conn, err := client_future.Get()
+ errs.Add(err)
+ err = errs.Finalize()
+ if err != nil {
+ if server_conn != nil {
+ server_conn.Close()
+ }
+ if client_conn != nil {
+ client_conn.(net.Conn).Close()
+ }
+ t.Fatal(err)
+ }
+ return server_conn, client_conn.(net.Conn)
+}
+
+type HandshakingConn interface {
+ net.Conn
+ Handshake() error
+}
+
+func SimpleConnTest(t testing.TB, constructor func(
+ t testing.TB, conn1, conn2 net.Conn) (sslconn1, sslconn2 HandshakingConn)) {
+ server_conn, client_conn := NetPipe(t)
+ defer server_conn.Close()
+ defer client_conn.Close()
+
+ data := "first test string\n"
+
+ server, client := constructor(t, server_conn, client_conn)
+ defer close_both(server, client)
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+
+ err := client.Handshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = io.Copy(client, bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = client.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+
+ err := server.Handshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ buf := bytes.NewBuffer(make([]byte, 0, len(data)))
+ _, err = io.CopyN(buf, server, int64(len(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(buf.Bytes()) != data {
+ t.Fatal("mismatched data")
+ }
+
+ err = server.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ wg.Wait()
+}
+
+func close_both(closer1, closer2 io.Closer) {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ closer1.Close()
+ }()
+ go func() {
+ defer wg.Done()
+ closer2.Close()
+ }()
+ wg.Wait()
+}
+
+func ClosingTest(t testing.TB, constructor func(
+ t testing.TB, conn1, conn2 net.Conn) (sslconn1, sslconn2 HandshakingConn)) {
+
+ run_test := func(close_tcp bool, server_writes bool) {
+ server_conn, client_conn := NetPipe(t)
+ defer server_conn.Close()
+ defer client_conn.Close()
+ server, client := constructor(t, server_conn, client_conn)
+ defer close_both(server, client)
+
+ var sslconn1, sslconn2 HandshakingConn
+ var conn1 net.Conn
+ if server_writes {
+ sslconn1 = server
+ conn1 = server_conn
+ sslconn2 = client
+ } else {
+ sslconn1 = client
+ conn1 = client_conn
+ sslconn2 = server
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ _, err := sslconn1.Write([]byte("hello"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if close_tcp {
+ err = conn1.Close()
+ } else {
+ err = sslconn1.Close()
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ go func() {
+ defer wg.Done()
+ data, err := ioutil.ReadAll(sslconn2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(data, []byte("hello")) {
+ t.Fatal("bytes don't match")
+ }
+ }()
+
+ wg.Wait()
+ }
+
+ run_test(true, false)
+ run_test(false, false)
+ run_test(true, true)
+ run_test(false, true)
+}
+
+func ThroughputBenchmark(b *testing.B, constructor func(
+ t testing.TB, conn1, conn2 net.Conn) (sslconn1, sslconn2 HandshakingConn)) {
+ server_conn, client_conn := NetPipe(b)
+ defer server_conn.Close()
+ defer client_conn.Close()
+
+ server, client := constructor(b, server_conn, client_conn)
+ defer close_both(server, client)
+
+ b.SetBytes(1024)
+ data := make([]byte, b.N*1024)
+ _, err := io.ReadFull(rand.Reader, data[:])
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ _, err = io.Copy(client, bytes.NewReader([]byte(data)))
+ if err != nil {
+ b.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+
+ buf := &bytes.Buffer{}
+ _, err = io.CopyN(buf, server, int64(len(data)))
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), data) {
+ b.Fatal("mismatched data")
+ }
+ }()
+ wg.Wait()
+ b.StopTimer()
+}
+
+func StdlibConstructor(t testing.TB, server_conn, client_conn net.Conn) (
+ server, client HandshakingConn) {
+ cert, err := tls.X509KeyPair(certBytes, keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ config := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ InsecureSkipVerify: true,
+ CipherSuites: []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}}
+ server = tls.Server(server_conn, config)
+ client = tls.Client(client_conn, config)
+ return server, client
+}
+
+func passThruVerify(t testing.TB) func(bool, *CertificateStoreCtx) bool {
+ x := func(ok bool, store *CertificateStoreCtx) bool {
+ cert := store.GetCurrentCert()
+ if cert == nil {
+ t.Fatalf("Could not obtain cert from store\n")
+ }
+ sn := cert.GetSerialNumberHex()
+ if len(sn) == 0 {
+ t.Fatalf("Could not obtain serial number from cert")
+ }
+ return ok
+ }
+ return x
+}
+
+func OpenSSLConstructor(t testing.TB, server_conn, client_conn net.Conn) (
+ server, client HandshakingConn) {
+ ctx, err := NewCtx()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ctx.SetVerify(VerifyNone, passThruVerify(t))
+ key, err := LoadPrivateKeyFromPEM(keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.UsePrivateKey(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := LoadCertificateFromPEM(certBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.UseCertificate(cert)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.SetCipherList("AES128-SHA")
+ if err != nil {
+ t.Fatal(err)
+ }
+ server, err = Server(server_conn, ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ client, err = Client(client_conn, ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return server, client
+}
+
+func StdlibOpenSSLConstructor(t testing.TB, server_conn, client_conn net.Conn) (
+ server, client HandshakingConn) {
+ server_std, _ := StdlibConstructor(t, server_conn, client_conn)
+ _, client_ssl := OpenSSLConstructor(t, server_conn, client_conn)
+ return server_std, client_ssl
+}
+
+func OpenSSLStdlibConstructor(t testing.TB, server_conn, client_conn net.Conn) (
+ server, client HandshakingConn) {
+ _, client_std := StdlibConstructor(t, server_conn, client_conn)
+ server_ssl, _ := OpenSSLConstructor(t, server_conn, client_conn)
+ return server_ssl, client_std
+}
+
+func TestStdlibSimple(t *testing.T) {
+ SimpleConnTest(t, StdlibConstructor)
+}
+
+func TestOpenSSLSimple(t *testing.T) {
+ SimpleConnTest(t, OpenSSLConstructor)
+}
+
+func TestStdlibClosing(t *testing.T) {
+ ClosingTest(t, StdlibConstructor)
+}
+
+func TestOpenSSLClosing(t *testing.T) {
+ ClosingTest(t, OpenSSLConstructor)
+}
+
+func BenchmarkStdlibThroughput(b *testing.B) {
+ ThroughputBenchmark(b, StdlibConstructor)
+}
+
+func BenchmarkOpenSSLThroughput(b *testing.B) {
+ ThroughputBenchmark(b, OpenSSLConstructor)
+}
+
+func TestStdlibOpenSSLSimple(t *testing.T) {
+ SimpleConnTest(t, StdlibOpenSSLConstructor)
+}
+
+func TestOpenSSLStdlibSimple(t *testing.T) {
+ SimpleConnTest(t, OpenSSLStdlibConstructor)
+}
+
+func TestStdlibOpenSSLClosing(t *testing.T) {
+ ClosingTest(t, StdlibOpenSSLConstructor)
+}
+
+func TestOpenSSLStdlibClosing(t *testing.T) {
+ ClosingTest(t, OpenSSLStdlibConstructor)
+}
+
+func BenchmarkStdlibOpenSSLThroughput(b *testing.B) {
+ ThroughputBenchmark(b, StdlibOpenSSLConstructor)
+}
+
+func BenchmarkOpenSSLStdlibThroughput(b *testing.B) {
+ ThroughputBenchmark(b, OpenSSLStdlibConstructor)
+}
+
+func FullDuplexRenegotiationTest(t testing.TB, constructor func(
+ t testing.TB, conn1, conn2 net.Conn) (sslconn1, sslconn2 HandshakingConn)) {
+
+ server_conn, client_conn := NetPipe(t)
+ defer server_conn.Close()
+ defer client_conn.Close()
+
+ times := 256
+ data_len := 4 * SSLRecordSize
+ data1 := make([]byte, data_len)
+ _, err := io.ReadFull(rand.Reader, data1[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ data2 := make([]byte, data_len)
+ _, err = io.ReadFull(rand.Reader, data1[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ server, client := constructor(t, server_conn, client_conn)
+ defer close_both(server, client)
+
+ var wg sync.WaitGroup
+
+ send_func := func(sender HandshakingConn, data []byte) {
+ defer wg.Done()
+ for i := 0; i < times; i++ {
+ if i == times/2 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ err := sender.Handshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ }
+ _, err := sender.Write(data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+
+ recv_func := func(receiver net.Conn, data []byte) {
+ defer wg.Done()
+
+ buf := make([]byte, len(data))
+ for i := 0; i < times; i++ {
+ n, err := io.ReadFull(receiver, buf[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf[:n], data) {
+ t.Fatal(err)
+ }
+ }
+ }
+
+ wg.Add(4)
+ go recv_func(server, data1)
+ go send_func(client, data1)
+ go send_func(server, data2)
+ go recv_func(client, data2)
+ wg.Wait()
+}
+
+func TestStdlibFullDuplexRenegotiation(t *testing.T) {
+ FullDuplexRenegotiationTest(t, StdlibConstructor)
+}
+
+func TestOpenSSLFullDuplexRenegotiation(t *testing.T) {
+ FullDuplexRenegotiationTest(t, OpenSSLConstructor)
+}
+
+func TestOpenSSLStdlibFullDuplexRenegotiation(t *testing.T) {
+ FullDuplexRenegotiationTest(t, OpenSSLStdlibConstructor)
+}
+
+func TestStdlibOpenSSLFullDuplexRenegotiation(t *testing.T) {
+ FullDuplexRenegotiationTest(t, StdlibOpenSSLConstructor)
+}
+
+func LotsOfConns(t *testing.T, payload_size int64, loops, clients int,
+ sleep time.Duration, newListener func(net.Listener) net.Listener,
+ newClient func(net.Conn) (net.Conn, error)) {
+ tcp_listener, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ ssl_listener := newListener(tcp_listener)
+ go func() {
+ for {
+ conn, err := ssl_listener.Accept()
+ if err != nil {
+ t.Fatalf("failed accept: %s", err)
+ continue
+ }
+ go func() {
+ defer func() {
+ err = conn.Close()
+ if err != nil {
+ t.Fatalf("failed closing: %s", err)
+ }
+ }()
+ for i := 0; i < loops; i++ {
+ _, err := io.Copy(ioutil.Discard,
+ io.LimitReader(conn, payload_size))
+ if err != nil {
+ t.Fatalf("failed reading: %s", err)
+ return
+ }
+ _, err = io.Copy(conn, io.LimitReader(rand.Reader,
+ payload_size))
+ if err != nil {
+ t.Fatalf("failed writing: %s", err)
+ return
+ }
+ }
+ time.Sleep(sleep)
+ }()
+ }
+ }()
+ var wg sync.WaitGroup
+ for i := 0; i < clients; i++ {
+ tcp_client, err := net.Dial(tcp_listener.Addr().Network(),
+ tcp_listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ ssl_client, err := newClient(tcp_client)
+ if err != nil {
+ t.Fatal(err)
+ }
+ wg.Add(1)
+ go func(i int) {
+ defer func() {
+ err = ssl_client.Close()
+ if err != nil {
+ t.Fatalf("failed closing: %s", err)
+ }
+ wg.Done()
+ }()
+ for i := 0; i < loops; i++ {
+ _, err := io.Copy(ssl_client, io.LimitReader(rand.Reader,
+ payload_size))
+ if err != nil {
+ t.Fatalf("failed writing: %s", err)
+ return
+ }
+ _, err = io.Copy(ioutil.Discard,
+ io.LimitReader(ssl_client, payload_size))
+ if err != nil {
+ t.Fatalf("failed reading: %s", err)
+ return
+ }
+ }
+ time.Sleep(sleep)
+ }(i)
+ }
+ wg.Wait()
+}
+
+func TestStdlibLotsOfConns(t *testing.T) {
+ tls_cert, err := tls.X509KeyPair(certBytes, keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tls_config := &tls.Config{
+ Certificates: []tls.Certificate{tls_cert},
+ InsecureSkipVerify: true,
+ CipherSuites: []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}}
+ LotsOfConns(t, 1024*64, 10, 100, 0*time.Second,
+ func(l net.Listener) net.Listener {
+ return tls.NewListener(l, tls_config)
+ }, func(c net.Conn) (net.Conn, error) {
+ return tls.Client(c, tls_config), nil
+ })
+}
+
+func TestOpenSSLLotsOfConns(t *testing.T) {
+ ctx, err := NewCtx()
+ if err != nil {
+ t.Fatal(err)
+ }
+ key, err := LoadPrivateKeyFromPEM(keyBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.UsePrivateKey(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := LoadCertificateFromPEM(certBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.UseCertificate(cert)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ctx.SetCipherList("AES128-SHA")
+ if err != nil {
+ t.Fatal(err)
+ }
+ LotsOfConns(t, 1024*64, 10, 100, 0*time.Second,
+ func(l net.Listener) net.Listener {
+ return NewListener(l, ctx)
+ }, func(c net.Conn) (net.Conn, error) {
+ return Client(c, ctx)
+ })
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/errors.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/errors.go
new file mode 100644
index 00000000000..bab314c95d7
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/errors.go
@@ -0,0 +1,50 @@
+// 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 utils
+
+import (
+ "errors"
+ "strings"
+)
+
+// ErrorGroup collates errors
+type ErrorGroup struct {
+ Errors []error
+}
+
+// Add adds an error to an existing error group
+func (e *ErrorGroup) Add(err error) {
+ if err != nil {
+ e.Errors = append(e.Errors, err)
+ }
+}
+
+// Finalize returns an error corresponding to the ErrorGroup state. If there's
+// no errors in the group, finalize returns nil. If there's only one error,
+// Finalize returns that error. Otherwise, Finalize will make a new error
+// consisting of the messages from the constituent errors.
+func (e *ErrorGroup) Finalize() error {
+ if len(e.Errors) == 0 {
+ return nil
+ }
+ if len(e.Errors) == 1 {
+ return e.Errors[0]
+ }
+ msgs := make([]string, 0, len(e.Errors))
+ for _, err := range e.Errors {
+ msgs = append(msgs, err.Error())
+ }
+ return errors.New(strings.Join(msgs, "\n"))
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/future.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/future.go
new file mode 100644
index 00000000000..fa1bbbfb861
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/utils/future.go
@@ -0,0 +1,79 @@
+// 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 utils
+
+import (
+ "sync"
+)
+
+// Future is a type that is essentially the inverse of a channel. With a
+// channel, you have multiple senders and one receiver. With a future, you can
+// have multiple receivers and one sender. Additionally, a future protects
+// against double-sends. Since this is usually used for returning function
+// results, we also capture and return error values as well. Use NewFuture
+// to initialize.
+type Future struct {
+ mutex *sync.Mutex
+ cond *sync.Cond
+ received bool
+ val interface{}
+ err error
+}
+
+// NewFuture returns an initialized and ready Future.
+func NewFuture() *Future {
+ mutex := &sync.Mutex{}
+ return &Future{
+ mutex: mutex,
+ cond: sync.NewCond(mutex),
+ received: false,
+ val: nil,
+ err: nil,
+ }
+}
+
+// Get blocks until the Future has a value set.
+func (self *Future) Get() (interface{}, error) {
+ self.mutex.Lock()
+ defer self.mutex.Unlock()
+ for {
+ if self.received {
+ return self.val, self.err
+ }
+ self.cond.Wait()
+ }
+}
+
+// Fired returns whether or not a value has been set. If Fired is true, Get
+// won't block.
+func (self *Future) Fired() bool {
+ self.mutex.Lock()
+ defer self.mutex.Unlock()
+ return self.received
+}
+
+// Set provides the value to present and future Get calls. If Set has already
+// been called, this is a no-op.
+func (self *Future) Set(val interface{}, err error) {
+ self.mutex.Lock()
+ defer self.mutex.Unlock()
+ if self.received {
+ return
+ }
+ self.received = true
+ self.val = val
+ self.err = err
+ self.cond.Broadcast()
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/verify.c b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/verify.c
new file mode 100644
index 00000000000..d55866c4cf0
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/verify.c
@@ -0,0 +1,31 @@
+// 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"
+
+int verify_cb(int ok, X509_STORE_CTX* store) {
+ SSL* ssl = (SSL *)X509_STORE_CTX_get_app_data(store);
+ 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);
+}
diff --git a/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/version.go b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/version.go
new file mode 100644
index 00000000000..8f3d392cde8
--- /dev/null
+++ b/src/mongo/gotools/vendor/src/github.com/spacemonkeygo/openssl/version.go
@@ -0,0 +1,22 @@
+// 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/opensslv.h>
+import "C"
+
+const Version string = C.OPENSSL_VERSION_TEXT