pax_global_header00006660000000000000000000000064137557552040014527gustar00rootroot0000000000000052 comment=9a076dd9dba79e7a1749df4e48ec9fce768d0122 golang-github-mendersoftware-openssl-1.1.0/000077500000000000000000000000001375575520400207615ustar00rootroot00000000000000golang-github-mendersoftware-openssl-1.1.0/.gitignore000066400000000000000000000000151375575520400227450ustar00rootroot00000000000000openssl.test golang-github-mendersoftware-openssl-1.1.0/.gitlab-ci.yml000066400000000000000000000107601375575520400234210ustar00rootroot00000000000000include: - project: 'Northern.tech/Mender/mendertesting' file: '.gitlab-ci-github-status-updates.yml' - project: 'Northern.tech/Mender/mendertesting' file: '.gitlab-ci-check-commits-signoffs.yml' stages: - test - publish test:unit: image: golang:1.14 stage: test before_script: # Rename the branch we're on, so that it's not in the way for the # subsequent fetch. It's ok if this fails, it just means we're not on any # branch. - git branch -m temp-branch || true # Git trick: Fetch directly into our local branches instead of remote # branches. - git fetch origin 'refs/heads/*:refs/heads/*' # Get last remaining tags, if any. - git fetch --tags origin # Prepare GO path - mkdir -p /go/src/github.com/mendersoftware - cp -r $CI_PROJECT_DIR /go/src/github.com/mendersoftware/openssl - cd /go/src/github.com/mendersoftware/openssl # Install code coverage / coveralls tooling - go get -u github.com/axw/gocov/gocov - go get -u golang.org/x/tools/cmd/cover # Install OpenSSL - apt-get update && apt-get install -yyq liblzma-dev libssl-dev # Install SoftHSM, OpenSC, GnuTLS - apt-get install -yyq softhsm2 opensc opensc-pkcs11 libengine-pkcs11-openssl gnutls-bin - mkdir -p /softhsm/tokens - echo "directories.tokendir = /softhsm/tokens" > /softhsm/softhsm2.conf - export SOFTHSM2_CONF=/softhsm/softhsm2.conf - softhsm2-util --init-token --free --label unittoken1 --pin 0001 --so-pin 0002 --slot 0 - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l -k --key-type rsa:2048 --id 0003 --label unittestkey0 --pin 0001 - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --show-info - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-slots - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-token-slots - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-mechanisms - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --list-objects - p11tool --login --provider=/usr/lib/softhsm/libsofthsm2.so --set-pin=0001 --list-all - export TEST_KEY_URI=`p11tool --login --provider=/usr/lib/softhsm/libsofthsm2.so --set-pin=0001 --list-all 2>/dev/null | grep type=private | awk '{print($NF";pin-value=0001");}'` - echo using $TEST_KEY_URI; - echo -ne "[openssl_init]\nengines=engine_section\n\n[engine_section]\npkcs11 = pkcs11_section\n\n[pkcs11_section]\nengine_id = pkcs11\nMODULE_PATH = /usr/lib/softhsm/libsofthsm2.so\ninit = 0\n" >> /etc/ssl/openssl.cnf - openssl req -new -x509 -subj "/CN=MenderUnits" -engine pkcs11 -keyform engine -key "${TEST_KEY_URI}" -out cert.pem script: # Test if code was formatted with 'go fmt' # Command will format code and return modified files # fail if any have been modified. - if [ -n "$(go fmt)" ]; then echo 'Code is not formatted with "go fmt"'; false; fi # Perform static code analysys - go vet `go list ./... | grep -v vendor` # go list supply import paths for all sub directories. # Exclude vendor directory, we don't want to run tests and coverage for all dependencies every time, # also including their coverage may introduce to much noice. Concentrate on the coverage of local packages. # Execute go test on every local subpackage (resolved as dependencies) and generate covreage report for each. # Test packages pararell (xargs -P) - export TEST_KEY_URI=`p11tool --login --provider=/usr/lib/softhsm/libsofthsm2.so --set-pin=0001 --list-all 2>/dev/null | grep type=private | awk '{print($NF";pin-value=0001");}'` - go test -parallel 1 -count 1 -v -covermode=atomic -coverprofile=coverage.txt -coverpkg ./... ./... || exit $? # Collect coverage reports - mkdir -p tests/unit-coverage && find . -name 'coverage.txt' -exec cp --parents {} ./tests/unit-coverage \; - tar -cvf $CI_PROJECT_DIR/unit-coverage.tar tests/unit-coverage artifacts: expire_in: 2w paths: - unit-coverage.tar publish:tests: image: golang:1.14-alpine3.11 stage: publish dependencies: - test:unit before_script: - apk add --no-cache git - cd / && go get github.com/mattn/goveralls && cd - - export CI_BRANCH=${CI_COMMIT_BRANCH} - export CI_PR_NUMBER=${CI_COMMIT_BRANCH#pr_} script: - tar -xvf unit-coverage.tar - goveralls -repotoken ${COVERALLS_TOKEN} -service gitlab-ci -jobid $CI_PIPELINE_ID -covermode set -flagname unittests -coverprofile $(find tests/unit-coverage -name 'coverage.txt' | tr '\n' ',' | sed 's/,$//') golang-github-mendersoftware-openssl-1.1.0/AUTHORS000066400000000000000000000016221375575520400220320ustar00rootroot00000000000000Andrew Brampton Anton Baklanov Carlos Martín Nieto Charles Strahan Christopher Dudley Christopher Fredericks Colin Misare dequis Gabriel Russell Giulio Jakob Unterwurzacher Juuso Haavisto kujenga Phus Lu Russ Egan Ryan Hileman Scott J. Goldman Scott Kidder Space Monkey, Inc Stephen Gallagher Viacheslav Biriukov Zack Owens Ramesh Rayaprolu Paras Shah Northern.tech golang-github-mendersoftware-openssl-1.1.0/LICENSE000066400000000000000000000240411375575520400217670ustar00rootroot00000000000000Apache 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. golang-github-mendersoftware-openssl-1.1.0/README.md000066400000000000000000000025151375575520400222430ustar00rootroot00000000000000# OpenSSL bindings for Go Please see http://godoc.org/github.com/spacemonkeygo/openssl for more info ### About This repository is a fork of [Space Monkey Go OpenSSL bindings](https://github.com/spacemonkeygo/openssl) maintained by Northern.tech. The project has been extended to cover more OpenSSL function calls. ### License Copyright (C) 2020 Northern.tech AS & others. See AUTHORS. 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 macOS 1. Install [homebrew](http://brew.sh/) 2. `$ brew install openssl` or `$ brew install openssl@1.1` ### 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) golang-github-mendersoftware-openssl-1.1.0/bio.go000066400000000000000000000145321375575520400220660ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" 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)) } var writeBioMapping = newMapping() type writeBio struct { data_mtx sync.Mutex op_mtx sync.Mutex buf []byte release_buffers bool } func loadWritePtr(b *C.BIO) *writeBio { t := token(C.X_BIO_get_data(b)) return (*writeBio)(writeBioMapping.Get(t)) } func bioClearRetryFlags(b *C.BIO) { C.X_BIO_clear_flags(b, C.BIO_FLAGS_RWS|C.BIO_FLAGS_SHOULD_RETRY) } func bioSetRetryRead(b *C.BIO) { C.X_BIO_set_flags(b, C.BIO_FLAGS_READ|C.BIO_FLAGS_SHOULD_RETRY) } //export go_write_bio_write func go_write_bio_write(b *C.BIO, data *C.char, size C.int) (rc C.int) { defer func() { if err := recover(); err != nil { 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 go_write_bio_ctrl func go_write_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) ( rc C.long) { defer func() { if err := recover(); err != nil { 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 { writeBioMapping.Del(token(C.X_BIO_get_data(b))) C.X_BIO_set_data(b, nil) } } func (b *writeBio) MakeCBIO() *C.BIO { rv := C.X_BIO_new_write_bio() token := writeBioMapping.Add(unsafe.Pointer(b)) C.X_BIO_set_data(rv, unsafe.Pointer(token)) return rv } var readBioMapping = newMapping() 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)(readBioMapping.Get(token(C.X_BIO_get_data(b)))) } //export go_read_bio_read func go_read_bio_read(b *C.BIO, data *C.char, size C.int) (rc C.int) { defer func() { if err := recover(); err != nil { 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 go_read_bio_ctrl func go_read_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) ( rc C.long) { defer func() { if err := recover(); err != nil { 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.X_BIO_new_read_bio() token := readBioMapping.Add(unsafe.Pointer(b)) C.X_BIO_set_data(rv, unsafe.Pointer(token)) return rv } func (self *readBio) Disconnect(b *C.BIO) { if loadReadPtr(b) == self { readBioMapping.Del(token(C.X_BIO_get_data(b))) C.X_BIO_set_data(b, 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.X_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.X_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 } golang-github-mendersoftware-openssl-1.1.0/build.go000066400000000000000000000017731375575520400224170ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 !openssl_static package openssl // #cgo linux windows pkg-config: libssl libcrypto // #cgo linux CFLAGS: -Wno-deprecated-declarations // #cgo darwin CFLAGS: -I/usr/local/opt/openssl@1.1/include -I/usr/local/opt/openssl/include -Wno-deprecated-declarations // #cgo darwin LDFLAGS: -L/usr/local/opt/openssl@1.1/lib -L/usr/local/opt/openssl/lib -lssl -lcrypto // #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN import "C" golang-github-mendersoftware-openssl-1.1.0/build_static.go000066400000000000000000000020031375575520400237510ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 openssl_static package openssl // #cgo linux windows pkg-config: --static libssl libcrypto // #cgo linux CFLAGS: -Wno-deprecated-declarations // #cgo darwin CFLAGS: -I/usr/local/opt/openssl@1.1/include -I/usr/local/opt/openssl/include -Wno-deprecated-declarations // #cgo darwin LDFLAGS: -L/usr/local/opt/openssl@1.1/lib -L/usr/local/opt/openssl/lib -lssl -lcrypto // #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN import "C" golang-github-mendersoftware-openssl-1.1.0/cert.go000066400000000000000000000266101375575520400222520ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" 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_MD4 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 ) // X509_Version represents a version on an x509 certificate. type X509_Version int // Specify constants for x509 versions because the standard states that they // are represented internally as one lower than the common version name. const ( X509_V1 X509_Version = 0 X509_V3 X509_Version = 2 ) 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, ) runtime.KeepAlive(n) 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) runtime.KeepAlive(n) 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") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(bn) if C.X509_set_serialNumber(c.x, sno) != 1 { return errors.New("failed to set serial") } runtime.KeepAlive(c) runtime.KeepAlive(sno) 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_X509_get0_notBefore(c.x), offset) if result == nil { return errors.New("failed to set issue date") } runtime.KeepAlive(c) 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_X509_get0_notAfter(c.x), offset) if result == nil { return errors.New("failed to set expire date") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(c) 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 = getDigestFunction(digest) if C.X509_sign(c.x, privKey.evpPKey(), md) <= 0 { return errors.New("failed to sign certificate") } runtime.KeepAlive(c) runtime.KeepAlive(privKey) runtime.KeepAlive(digest) return nil } func getDigestFunction(digest EVP_MD) (md *C.EVP_MD) { switch digest { // please don't use these digest functions case EVP_NULL: md = C.X_EVP_md_null() case EVP_MD5: md = C.X_EVP_md5() case EVP_SHA: md = C.X_EVP_sha() case EVP_SHA1: md = C.X_EVP_sha1() case EVP_DSS: md = C.X_EVP_dss() case EVP_DSS1: md = C.X_EVP_dss1() case EVP_RIPEMD160: md = C.X_EVP_ripemd160() case EVP_SHA224: md = C.X_EVP_sha224() // you actually want one of these case EVP_SHA256: md = C.X_EVP_sha256() case EVP_SHA384: md = C.X_EVP_sha384() case EVP_SHA512: md = C.X_EVP_sha512() } return md } // 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") } runtime.KeepAlive(c) 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") } runtime.KeepAlive(c) 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) runtime.KeepAlive(c) 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) runtime.KeepAlive(c) C.BN_free(bignum) C.X_OPENSSL_free(unsafe.Pointer(hex)) return } // GetVersion returns the X509 version of the certificate. func (c *Certificate) GetVersion() X509_Version { version := C.X_X509_get_version(c.x) runtime.KeepAlive(c) return X509_Version(version) } // SetVersion sets the X509 version of the certificate. func (c *Certificate) SetVersion(version X509_Version) error { cvers := C.long(version) if C.X_X509_set_version(c.x, cvers) != 1 { return errors.New("failed to set certificate version") } runtime.KeepAlive(c) return nil } golang-github-mendersoftware-openssl-1.1.0/cert_test.go000066400000000000000000000073501375575520400233110ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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(768) 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(768) 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(768) 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(768) 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) } } func TestCertVersion(t *testing.T) { key, err := GenerateRSAKey(768) 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.SetVersion(X509_V3); err != nil { t.Fatal(err) } if vers := cert.GetVersion(); vers != X509_V3 { t.Fatalf("bad version: %d", vers) } } golang-github-mendersoftware-openssl-1.1.0/ciphers.go000066400000000000000000000216071375575520400227530ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" 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.X_EVP_CIPHER_nid(c.ptr)) } func (c *Cipher) ShortName() (string, error) { return Nid2ShortName(c.Nid()) } func (c *Cipher) BlockSize() int { return int(C.X_EVP_CIPHER_block_size(c.ptr)) } func (c *Cipher) KeySize() int { return int(C.X_EVP_CIPHER_key_length(c.ptr)) } func (c *Cipher) IVSize() int { return int(C.X_EVP_CIPHER_iv_length(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) } // EVP_CIPHER type uses static mem; no 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 C.X_EVP_CIPHER_CTX_encrypting(ctx.ctx) != 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") } } runtime.KeepAlive(ctx) runtime.KeepAlive(key) runtime.KeepAlive(iv) return nil } func (ctx *cipherCtx) Cipher() *Cipher { cipher := C.X_EVP_CIPHER_CTX_cipher(ctx.ctx) runtime.KeepAlive(ctx) return &Cipher{ptr: cipher} } func (ctx *cipherCtx) BlockSize() int { blockSize := C.X_EVP_CIPHER_CTX_block_size(ctx.ctx) runtime.KeepAlive(ctx) return int(blockSize) } func (ctx *cipherCtx) KeySize() int { keySize := C.X_EVP_CIPHER_CTX_key_length(ctx.ctx) runtime.KeepAlive(ctx) return int(keySize) } func (ctx *cipherCtx) IVSize() int { ivSize := C.X_EVP_CIPHER_CTX_iv_length(ctx.ctx) runtime.KeepAlive(ctx) return int(ivSize) } func (ctx *cipherCtx) SetPadding(pad bool) { if pad { C.X_EVP_CIPHER_CTX_set_padding(ctx.ctx, 1) } else { C.X_EVP_CIPHER_CTX_set_padding(ctx.ctx, 0) } runtime.KeepAlive(ctx) } func (ctx *cipherCtx) setCtrl(code, arg int) error { res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), nil) runtime.KeepAlive(ctx) 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) } runtime.KeepAlive(ctx) runtime.KeepAlive(value) 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)) runtime.KeepAlive(ctx) 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]), ) runtime.KeepAlive(ctx) 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") } runtime.KeepAlive(e) runtime.KeepAlive(c) 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") } runtime.KeepAlive(e) runtime.KeepAlive(c) 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) { if len(input) == 0 { return nil, nil } 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) } runtime.KeepAlive(ctx) runtime.KeepAlive(input) return outbuf[:outlen], nil } func (ctx *decryptionCipherCtx) DecryptUpdate(input []byte) ([]byte, error) { if len(input) == 0 { return nil, nil } 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) } runtime.KeepAlive(ctx) runtime.KeepAlive(input) 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") } runtime.KeepAlive(ctx) 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") } runtime.KeepAlive(ctx) return outbuf[:outlen], nil } golang-github-mendersoftware-openssl-1.1.0/ciphers_gcm.go000066400000000000000000000103251375575520400235740ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include import "C" import ( "errors" "fmt" "runtime" ) type AuthenticatedEncryptionCipherCtx interface { EncryptionCipherCtx // data passed in to ExtraData() is part of the final output; it is // not encrypted itself, but is part of the authenticated data. when // decrypting or authenticating, pass back with the decryption // context's ExtraData() ExtraData([]byte) error // use after finalizing encryption to get the authenticating tag GetTag() ([]byte, error) } type AuthenticatedDecryptionCipherCtx interface { DecryptionCipherCtx // pass in any extra data that was added during encryption with the // encryption context's ExtraData() ExtraData([]byte) error // use before finalizing decryption to tell the library what the // tag is expected to be SetTag([]byte) error } type authEncryptionCipherCtx struct { *encryptionCipherCtx } type authDecryptionCipherCtx struct { *decryptionCipherCtx } func getGCMCipher(blocksize int) (*Cipher, error) { var cipherptr *C.EVP_CIPHER switch blocksize { case 256: cipherptr = C.EVP_aes_256_gcm() case 192: cipherptr = C.EVP_aes_192_gcm() case 128: cipherptr = C.EVP_aes_128_gcm() default: return nil, fmt.Errorf("unknown block size %d", blocksize) } return &Cipher{ptr: cipherptr}, nil } func NewGCMEncryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( AuthenticatedEncryptionCipherCtx, error) { cipher, err := getGCMCipher(blocksize) if err != nil { return nil, err } ctx, err := newEncryptionCipherCtx(cipher, e, key, nil) if err != nil { return nil, err } if len(iv) > 0 { err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) if err != nil { return nil, fmt.Errorf("could not set IV len to %d: %s", len(iv), err) } if 1 != C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, nil, (*C.uchar)(&iv[0])) { return nil, errors.New("failed to apply IV") } runtime.KeepAlive(ctx) runtime.KeepAlive(iv) } return &authEncryptionCipherCtx{encryptionCipherCtx: ctx}, nil } func NewGCMDecryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( AuthenticatedDecryptionCipherCtx, error) { cipher, err := getGCMCipher(blocksize) if err != nil { return nil, err } ctx, err := newDecryptionCipherCtx(cipher, e, key, nil) if err != nil { return nil, err } if len(iv) > 0 { err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) if err != nil { return nil, fmt.Errorf("could not set IV len to %d: %s", len(iv), err) } if 1 != C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, nil, (*C.uchar)(&iv[0])) { return nil, errors.New("failed to apply IV") } runtime.KeepAlive(ctx) runtime.KeepAlive(iv) } return &authDecryptionCipherCtx{decryptionCipherCtx: ctx}, nil } func (ctx *authEncryptionCipherCtx) ExtraData(aad []byte) error { if aad == nil { return nil } var outlen C.int if 1 != C.EVP_EncryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), C.int(len(aad))) { return errors.New("failed to add additional authenticated data") } runtime.KeepAlive(ctx) runtime.KeepAlive(aad) return nil } func (ctx *authDecryptionCipherCtx) ExtraData(aad []byte) error { if aad == nil { return nil } var outlen C.int if 1 != C.EVP_DecryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), C.int(len(aad))) { return errors.New("failed to add additional authenticated data") } runtime.KeepAlive(ctx) runtime.KeepAlive(aad) return nil } func (ctx *authEncryptionCipherCtx) GetTag() ([]byte, error) { return ctx.getCtrlBytes(C.EVP_CTRL_GCM_GET_TAG, GCM_TAG_MAXLEN, GCM_TAG_MAXLEN) } func (ctx *authDecryptionCipherCtx) SetTag(tag []byte) error { return ctx.setCtrlBytes(C.EVP_CTRL_GCM_SET_TAG, len(tag), tag) } golang-github-mendersoftware-openssl-1.1.0/ciphers_test.go000066400000000000000000000217331375575520400240120ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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" "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) } golang-github-mendersoftware-openssl-1.1.0/conn.go000066400000000000000000000531321375575520400222510ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "errors" "fmt" "io" "net" "runtime" "sync" "time" "unsafe" "github.com/mendersoftware/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 { *SSL conn net.Conn 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 CertificateAuthorityKeyTooSmall VerifyResult = C.X509_V_ERR_CA_KEY_TOO_SMALL CertificateAuthorityMessageDigestTooWeak VerifyResult = C.X509_V_ERR_CA_MD_TOO_WEAK RevocationListPathValidationError VerifyResult = C.X509_V_ERR_CRL_PATH_VALIDATION_ERROR DomanNameAuthenticationNamedEntitiesNoMatch VerifyResult = C.X509_V_ERR_DANE_NO_MATCH RevocationListDifferentScope VerifyResult = C.X509_V_ERR_DIFFERENT_CRL_SCOPE EndEntityKeyTooSmall VerifyResult = C.X509_V_ERR_EE_KEY_TOO_SMALL EmailMismatch VerifyResult = C.X509_V_ERR_EMAIL_MISMATCH ExcludedViolation VerifyResult = C.X509_V_ERR_EXCLUDED_VIOLATION HostnameMismatch VerifyResult = C.X509_V_ERR_HOSTNAME_MISMATCH InvalidCall VerifyResult = C.X509_V_ERR_INVALID_CALL IpAddressMismatch VerifyResult = C.X509_V_ERR_IP_ADDRESS_MISMATCH NoValidSignedCertificateTimestamps VerifyResult = C.X509_V_ERR_NO_VALID_SCTS /* OnlineCertificateStatusCertificateUnknown VerifyResult = C.X509_V_ERR_OCSP_CERT_UNKNOWN OnlineCertificateStatusVerifyFailed VerifyResult = C.X509_V_ERR_OCSP_VERIFY_FAILED OnlineCertificateStatusVerifyNeeded VerifyResult = C.X509_V_ERR_OCSP_VERIFY_NEEDED */ //the above are not present on v1.1.0 it is a quick fix to maintain the compatibility PathLoopError VerifyResult = C.X509_V_ERR_PATH_LOOP PermittedViolation VerifyResult = C.X509_V_ERR_PERMITTED_VIOLATION ProxySubjectNameViolation VerifyResult = C.X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION StoreLookupError VerifyResult = C.X509_V_ERR_STORE_LOOKUP SubTreMinMax VerifyResult = C.X509_V_ERR_SUBTREE_MINMAX SuiteBCannotSignP384WithP256 VerifyResult = C.X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 SuiteBInvalidAlgorithm VerifyResult = C.X509_V_ERR_SUITE_B_INVALID_ALGORITHM SuiteBInvalidCurve VerifyResult = C.X509_V_ERR_SUITE_B_INVALID_CURVE SuiteBInvalidSignatureAlgorithm VerifyResult = C.X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM SuiteBInvalidVersion VerifyResult = C.X509_V_ERR_SUITE_B_INVALID_VERSION SuiteBLosNotAllowed VerifyResult = C.X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED SuiteBUnspecifiedError VerifyResult = C.X509_V_ERR_UNSPECIFIED UnsupportedConstraintSyntax VerifyResult = C.X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX UnsupportedConstraintType VerifyResult = C.X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE UnsupportedExtensionFeature VerifyResult = C.X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE UnsupportedNameSyntax VerifyResult = C.X509_V_ERR_UNSUPPORTED_NAME_SYNTAX ) 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 // FIXME: memory leak: MakeCBIO maintains a mapping of // *C.BIO types making GC keep the map entry. 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) s := &SSL{ssl: ssl} //go vet complains here: //173:42: possibly passing Go type with embedded pointer to C u := unsafe.Pointer(s) C.SSL_set_ex_data(s.ssl, get_ssl_idx(), u) c := &Conn{ SSL: s, conn: conn, ctx: ctx, into_ssl: into_ssl, from_ssl: from_ssl} runtime.SetFinalizer(c, func(c *Conn) { // FIXME: memory leak: C.BIO_free never called 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) GetCtx() *Ctx { return c.ctx } func (c *Conn) CurrentCipher() (string, error) { p := C.X_SSL_get_cipher_name(c.ssl) runtime.KeepAlive(c) 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) runtime.KeepAlive(c) 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) runtime.KeepAlive(c) 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) runtime.KeepAlive(c) 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 } // loadCertificateStack loads up a stack of x509 certificates and returns them, // handling memory ownership. func (c *Conn) loadCertificateStack(sk *C.struct_stack_st_X509) ( rv []*Certificate) { sk_num := int(C.X_sk_X509_num(sk)) rv = make([]*Certificate, 0, sk_num) for i := 0; i < sk_num; i++ { x := C.X_sk_X509_value(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 } // 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) runtime.KeepAlive(c) if sk == nil { return nil, errors.New("no peer certificates found") } return c.loadCertificateStack(sk), 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) runtime.KeepAlive(c) 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))) runtime.KeepAlive(c) runtime.KeepAlive(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))) runtime.KeepAlive(c) runtime.KeepAlive(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) SetTlsExtHostName(name string) error { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) runtime.LockOSThread() defer runtime.UnlockOSThread() if C.X_SSL_set_tlsext_host_name(c.ssl, cname) == 0 { return errorFromErrorQueue() } runtime.KeepAlive(c) return nil } func (c *Conn) VerifyResult() VerifyResult { res := C.SSL_get_verify_result(c.ssl) runtime.KeepAlive(c) return VerifyResult(res) } func (c *Conn) SessionReused() bool { reused := C.X_SSL_session_reused(c.ssl) == 1 runtime.KeepAlive(reused) return reused } 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)) runtime.KeepAlive(c) 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) runtime.KeepAlive(c) if ret != 1 { return fmt.Errorf("unable to set session: %s", errorFromErrorQueue()) } return nil } golang-github-mendersoftware-openssl-1.1.0/ctx.go000066400000000000000000000425111375575520400221110ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include // #include "shim.h" import "C" import ( "errors" "fmt" "io/ioutil" "os" "runtime" "sync" "time" "unsafe" ) var ( ssl_ctx_idx = C.X_SSL_CTX_new_index() ) type Ctx struct { ctx *C.SSL_CTX cert *Certificate chain []*Certificate key PrivateKey verify_cb VerifyCallback sni_cb TLSExtServernameCallback ticket_store_mu sync.Mutex ticket_store *TicketStore } //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} //go vet complains here: //63:48: possibly passing Go type with embedded pointer to C u := unsafe.Pointer(c) C.SSL_CTX_set_ex_data(ctx, get_ssl_ctx_idx(), u) 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 SSLv3: method = C.X_SSLv3_method() case TLSv1: method = C.X_TLSv1_method() case TLSv1_1: method = C.X_TLSv1_1_method() case TLSv1_2: method = C.X_TLSv1_2_method() case AnyVersion: method = C.X_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 // P-521: NIST/SECG curve over a 521 bit prime field Secp521r1 EllipticCurve = C.NID_secp521r1 ) // SetEllipticCurve sets the elliptic curve used by the SSL context to // enable an ECDH cipher suite to be selected during the handshake. func (c *Ctx) SetEllipticCurve(curve EllipticCurve) error { runtime.LockOSThread() defer runtime.UnlockOSThread() k := C.EC_KEY_new_by_curve_name(C.int(curve)) if k == nil { return errors.New("Unknown curve") } defer C.EC_KEY_free(k) if int(C.X_SSL_CTX_set_tmp_ecdh(c.ctx, k)) != 1 { return errorFromErrorQueue() } runtime.KeepAlive(c) return nil } // 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() } runtime.KeepAlive(c) return nil } // 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.X_SSL_CTX_add_extra_chain_cert(c.ctx, cert.x)) != 1 { return errorFromErrorQueue() } runtime.KeepAlive(c) // 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() } runtime.KeepAlive(c) runtime.KeepAlive(key) 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() } runtime.KeepAlive(s) runtime.KeepAlive(cert) return nil } type CertificateStoreCtx struct { ctx *C.X509_STORE_CTX ssl_ctx *Ctx } func (self *CertificateStoreCtx) VerifyResult() VerifyResult { result := C.X509_STORE_CTX_get_error(self.ctx) runtime.KeepAlive(self) return VerifyResult(result) } func (self *CertificateStoreCtx) Err() error { code := C.X509_STORE_CTX_get_error(self.ctx) runtime.KeepAlive(self) 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 { depth := C.X509_STORE_CTX_get_error_depth(self.ctx) runtime.KeepAlive(self) return int(depth) } // 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) runtime.KeepAlive(self) if x509 == nil { return nil } // add a ref if 1 != C.X_X509_add_ref(x509) { return nil } 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() } runtime.KeepAlive(c) return nil } type Options int 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 NoTicket Options = C.SSL_OP_NO_TICKET ) // SetOptions sets context options. See // http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html func (c *Ctx) SetOptions(options Options) Options { opts := C.X_SSL_CTX_set_options( c.ctx, C.long(options), ) runtime.KeepAlive(c) return Options(opts) } func (c *Ctx) ClearOptions(options Options) Options { opts := C.X_SSL_CTX_clear_options( c.ctx, C.long(options), ) runtime.KeepAlive(c) return Options(opts) } // GetOptions returns context options. See // https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html func (c *Ctx) GetOptions() Options { opts := C.X_SSL_CTX_get_options(c.ctx) runtime.KeepAlive(c) return Options(opts) } 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 ) // SetMode sets context modes. See // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html func (c *Ctx) SetMode(modes Modes) Modes { mode := C.X_SSL_CTX_set_mode(c.ctx, C.long(modes)) runtime.KeepAlive(c) return Modes(mode) } // GetMode returns context modes. See // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html func (c *Ctx) GetMode() Modes { mode := C.X_SSL_CTX_get_mode(c.ctx) runtime.KeepAlive(c) return Modes(mode) } 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 VerifyCallback func(ok bool, store *CertificateStoreCtx) bool //export go_ssl_ctx_verify_cb_thunk func go_ssl_ctx_verify_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int { defer func() { if err := recover(); err != nil { 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.X_SSL_CTX_verify_cb)) } else { C.SSL_CTX_set_verify(c.ctx, C.int(options), nil) } runtime.KeepAlive(c) } 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 { opts := C.SSL_CTX_get_verify_mode(c.ctx) runtime.KeepAlive(c) return VerifyOptions(opts) } // 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)) runtime.KeepAlive(c) } // 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 { depth := C.SSL_CTX_get_verify_depth(c.ctx) runtime.KeepAlive(c) return int(depth) } type TLSExtServernameCallback func(ssl *SSL) SSLTLSExtErr // SetTLSExtServernameCallback sets callback function for Server Name Indication // (SNI) rfc6066 (http://tools.ietf.org/html/rfc6066). See // http://stackoverflow.com/questions/22373332/serving-multiple-domains-in-one-box-with-sni func (c *Ctx) SetTLSExtServernameCallback(sni_cb TLSExtServernameCallback) { c.sni_cb = sni_cb C.X_SSL_CTX_set_tlsext_servername_callback(c.ctx, (*[0]byte)(C.sni_cb)) runtime.KeepAlive(c) } 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() } runtime.KeepAlive(c) runtime.KeepAlive(session_id) 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() } runtime.KeepAlive(c) 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 { cacheModes := C.X_SSL_CTX_set_session_cache_mode(c.ctx, C.long(modes)) runtime.KeepAlive(c) return SessionCacheModes(cacheModes) } // 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.X_SSL_CTX_set_timeout(c.ctx, C.long(t/time.Second)) runtime.KeepAlive(c) 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 { timeout := time.Duration(C.X_SSL_CTX_get_timeout(c.ctx)) * time.Second runtime.KeepAlive(c) return timeout } // 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 { ret := C.X_SSL_CTX_sess_set_cache_size(c.ctx, C.long(t)) runtime.KeepAlive(c) return int(ret) } // Get session cache size. // https://www.openssl.org/docs/ssl/SSL_CTX_sess_set_cache_size.html func (c *Ctx) SessGetCacheSize() int { cacheSize := C.X_SSL_CTX_sess_get_cache_size(c.ctx) runtime.KeepAlive(c) return int(cacheSize) } // SetDefaultVerifyPaths // https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_default_verify_paths.html // enables automatic loading of the default trust store from the `certs' subdirectory // and `cert.pem' file in the OPENSSL_DIR (check with `openssl version -d') func (c *Ctx) SetDefaultVerifyPaths() error { runtime.LockOSThread() defer runtime.UnlockOSThread() ret := C.SSL_CTX_set_default_verify_paths(c.ctx) if ret == 0 { return errorFromErrorQueue() } return nil } // GetDefaultCertificateDirectory returns the default directory for the system // certificates. func GetDefaultCertificateDirectory() (string, error) { dir := C.GoString(C.X509_get_default_cert_dir()) if dir == "" { return "", errors.New("Failed to get the OpenSSL directory variable") } return dir, nil } golang-github-mendersoftware-openssl-1.1.0/ctx_test.go000066400000000000000000000053741375575520400231560ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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" "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") } } func TestCtxSetDefaultVerifyLocations(t *testing.T) { _, err := http.Head("https://example.com") if err != nil { t.Skipf("Get: err: %v", err) } ctx, err := NewCtx() if err != nil { t.Error("cant create context") } conn, err := Dial("tcp", "google.com:443", ctx, 0) if err != nil { t.Fatalf("Failed to dial google.com:443. err: %v", err) } v := conn.VerifyResult() if v != UnableToGetIssuerCertLocally { t.Errorf("expected: UnableToGetIssuerCertLocally, got: %d", v) } ctx, err = NewCtx() if err != nil { t.Error("cant create context") } if err := ctx.SetDefaultVerifyPaths(); err != nil { t.Errorf("set_default_verify_paths OpenSSL call failed: %v", err) } conn, err = Dial("tcp", "google.com:443", ctx, 0) if err != nil { t.Fatalf("Failed to dial google.com:443. err: %v", err) } v = conn.VerifyResult() if v != Ok { t.Errorf("expected: Ok, got: %d", v) } } // TestGetDefaultCertificateDirectory returns the default directory for CA // certificates on the system. func TestGetDefaultCertificateDirectory(t *testing.T) { defDir, err := GetDefaultCertificateDirectory() if err != nil { t.Errorf("Failed to get the default certificate directory. '%v'", err) } if len(defDir) == 0 { t.Errorf("Error: GetDefaultCertificateDirectory() returned a zero length string, but no error") } } golang-github-mendersoftware-openssl-1.1.0/dh.go000066400000000000000000000043341375575520400217070ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "errors" "runtime" "unsafe" ) // DeriveSharedSecret derives a shared secret using a private key and a peer's // public key. // The specific algorithm that is used depends on the types of the // keys, but it is most commonly a variant of Diffie-Hellman. func DeriveSharedSecret(private PrivateKey, public PublicKey) ([]byte, error) { // Create context for the shared secret derivation dhCtx := C.EVP_PKEY_CTX_new(private.evpPKey(), nil) runtime.KeepAlive(private) if dhCtx == nil { return nil, errors.New("failed creating shared secret derivation context") } defer C.EVP_PKEY_CTX_free(dhCtx) // Initialize the context if int(C.EVP_PKEY_derive_init(dhCtx)) != 1 { return nil, errors.New("failed initializing shared secret derivation context") } // Provide the peer's public key if int(C.EVP_PKEY_derive_set_peer(dhCtx, public.evpPKey())) != 1 { return nil, errors.New("failed adding peer public key to context") } runtime.KeepAlive(public) // Determine how large of a buffer we need for the shared secret var buffLen C.size_t if int(C.EVP_PKEY_derive(dhCtx, nil, &buffLen)) != 1 { return nil, errors.New("failed determining shared secret length") } // Allocate a buffer buffer := C.X_OPENSSL_malloc(buffLen) if buffer == nil { return nil, errors.New("failed allocating buffer for shared secret") } defer C.X_OPENSSL_free(buffer) // Derive the shared secret if int(C.EVP_PKEY_derive(dhCtx, (*C.uchar)(buffer), &buffLen)) != 1 { return nil, errors.New("failed deriving the shared secret") } secret := C.GoBytes(unsafe.Pointer(buffer), C.int(buffLen)) return secret, nil } golang-github-mendersoftware-openssl-1.1.0/dh_test.go000066400000000000000000000021351375575520400227430ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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" "testing" ) func TestECDH(t *testing.T) { t.Parallel() myKey, err := GenerateECKey(Prime256v1) if err != nil { t.Fatal(err) } peerKey, err := GenerateECKey(Prime256v1) if err != nil { t.Fatal(err) } mySecret, err := DeriveSharedSecret(myKey, peerKey) if err != nil { t.Fatal(err) } theirSecret, err := DeriveSharedSecret(peerKey, myKey) if err != nil { t.Fatal(err) } if bytes.Compare(mySecret, theirSecret) != 0 { t.Fatal("shared secrets are different") } } golang-github-mendersoftware-openssl-1.1.0/dhparam.go000066400000000000000000000033421375575520400227260ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" 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.X_SSL_CTX_set_tmp_dh(c.ctx, dh.dh)) != 1 { return errorFromErrorQueue() } runtime.KeepAlive(c) runtime.KeepAlive(dh) return nil } golang-github-mendersoftware-openssl-1.1.0/digest.go000066400000000000000000000026361375575520400225760ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.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.X_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) } golang-github-mendersoftware-openssl-1.1.0/engine.go000066400000000000000000000022401375575520400225530ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 /* #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 } golang-github-mendersoftware-openssl-1.1.0/fips.go000066400000000000000000000020061375575520400222470ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 /* #include */ import "C" import "runtime" // FIPSModeSet enables a FIPS 140-2 validated mode of operation. // https://wiki.openssl.org/index.php/FIPS_mode_set() func FIPSModeSet(mode bool) error { runtime.LockOSThread() defer runtime.UnlockOSThread() 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 } golang-github-mendersoftware-openssl-1.1.0/go.mod000066400000000000000000000000511375575520400220630ustar00rootroot00000000000000module github.com/mendersoftware/openssl golang-github-mendersoftware-openssl-1.1.0/go.sum000066400000000000000000000000001375575520400221020ustar00rootroot00000000000000golang-github-mendersoftware-openssl-1.1.0/hmac.go000066400000000000000000000044651375575520400222310ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "errors" "runtime" "unsafe" ) type HMAC struct { ctx *C.HMAC_CTX engine *Engine md *C.EVP_MD } func NewHMAC(key []byte, digestAlgorithm EVP_MD) (*HMAC, error) { return NewHMACWithEngine(key, digestAlgorithm, nil) } func NewHMACWithEngine(key []byte, digestAlgorithm EVP_MD, e *Engine) (*HMAC, error) { var md *C.EVP_MD = getDigestFunction(digestAlgorithm) h := &HMAC{engine: e, md: md} h.ctx = C.X_HMAC_CTX_new() if h.ctx == nil { return nil, errors.New("unable to allocate HMAC_CTX") } var c_e *C.ENGINE if e != nil { c_e = e.e } if rc := C.X_HMAC_Init_ex(h.ctx, unsafe.Pointer(&key[0]), C.int(len(key)), md, c_e); rc != 1 { C.X_HMAC_CTX_free(h.ctx) return nil, errors.New("failed to initialize HMAC_CTX") } runtime.SetFinalizer(h, func(h *HMAC) { h.Close() }) return h, nil } func (h *HMAC) Close() { C.X_HMAC_CTX_free(h.ctx) } func (h *HMAC) Write(data []byte) (n int, err error) { if len(data) == 0 { return 0, nil } if rc := C.X_HMAC_Update(h.ctx, (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data))); rc != 1 { return 0, errors.New("failed to update HMAC") } runtime.KeepAlive(h) return len(data), nil } func (h *HMAC) Reset() error { if 1 != C.X_HMAC_Init_ex(h.ctx, nil, 0, nil, nil) { return errors.New("failed to reset HMAC_CTX") } runtime.KeepAlive(h) return nil } func (h *HMAC) Final() (result []byte, err error) { mdLength := C.X_EVP_MD_size(h.md) result = make([]byte, mdLength) if rc := C.X_HMAC_Final(h.ctx, (*C.uchar)(unsafe.Pointer(&result[0])), (*C.uint)(unsafe.Pointer(&mdLength))); rc != 1 { return nil, errors.New("failed to finalized HMAC") } runtime.KeepAlive(result) return result, h.Reset() } golang-github-mendersoftware-openssl-1.1.0/hmac_test.go000066400000000000000000000037131375575520400232630ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "crypto/hmac" "crypto/sha256" "encoding/hex" "testing" ) func TestSHA256HMAC(t *testing.T) { key := []byte("d741787cc61851af045ccd37") data := []byte("5912EEFD-59EC-43E3-ADB8-D5325AEC3271") h, err := NewHMAC(key, EVP_SHA256) if err != nil { t.Fatalf("Unable to create new HMAC: %s", err) } if _, err := h.Write(data); err != nil { t.Fatalf("Unable to write data into HMAC: %s", err) } var actualHMACBytes []byte if actualHMACBytes, err = h.Final(); err != nil { t.Fatalf("Error while finalizing HMAC: %s", err) } actualString := hex.EncodeToString(actualHMACBytes) // generate HMAC with built-in crypto lib mac := hmac.New(sha256.New, key) mac.Write(data) expectedString := hex.EncodeToString(mac.Sum(nil)) if expectedString != actualString { t.Errorf("HMAC was incorrect: expected=%s, actual=%s", expectedString, actualString) } } func BenchmarkSHA256HMAC(b *testing.B) { key := []byte("d741787cc61851af045ccd37") data := []byte("5912EEFD-59EC-43E3-ADB8-D5325AEC3271") h, err := NewHMAC(key, EVP_SHA256) if err != nil { b.Fatalf("Unable to create new HMAC: %s", err) } b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := h.Write(data); err != nil { b.Fatalf("Unable to write data into HMAC: %s", err) } var err error if _, err = h.Final(); err != nil { b.Fatalf("Error while finalizing HMAC: %s", err) } } } golang-github-mendersoftware-openssl-1.1.0/hostname.c000066400000000000000000000252241375575520400227500ustar00rootroot00000000000000/* * 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 #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 #include #include #include #include #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; } #if OPENSSL_VERSION_NUMBER < 0x1000200fL int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen, unsigned int flags, char **peername) { 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 /* OPENSSL_VERSION_NUMBER < 0x1000200fL */ #endif golang-github-mendersoftware-openssl-1.1.0/hostname.go000066400000000000000000000102001375575520400231170ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 /* #include #include #include #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, char **peername); 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" "runtime" "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), nil) runtime.KeepAlive(c) 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)) runtime.KeepAlive(c) 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 { // X509_check_ip will fail to validate the 16-byte representation of an IPv4 // address, so convert to the 4-byte representation. if ip4 := ip.To4(); ip4 != nil { ip = ip4 } cip := unsafe.Pointer(&ip[0]) rv := C.X509_check_ip(c.x, (*C.uchar)(cip), C.size_t(len(ip)), C.uint(flags)) runtime.KeepAlive(c) 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) } golang-github-mendersoftware-openssl-1.1.0/http.go000066400000000000000000000041711375575520400222720ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 golang-github-mendersoftware-openssl-1.1.0/init.go000066400000000000000000000076641375575520400222700ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 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 "shim.h" import "C" import ( "errors" "fmt" "strings" ) func init() { if rc := C.X_shim_init(); rc != 0 { panic(fmt.Errorf("X_shim_init 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"))) } golang-github-mendersoftware-openssl-1.1.0/init_posix.go000066400000000000000000000031321375575520400234740ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 solaris // +build !windows package openssl /* #include #include #include pthread_mutex_t* goopenssl_locks; int go_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 go_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]); } } unsigned long go_thread_id_callback(void) { return (unsigned long)pthread_self(); } */ import "C" golang-github-mendersoftware-openssl-1.1.0/init_windows.go000066400000000000000000000026031375575520400240260ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 package openssl /* #include #include #include CRITICAL_SECTION* goopenssl_locks; int go_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 go_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]); } } unsigned long go_thread_id_callback(void) { return (unsigned long)GetCurrentThreadId(); } */ import "C" golang-github-mendersoftware-openssl-1.1.0/key.go000066400000000000000000000377471375575520400221220ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "openssl/engine.h" // #include "shim.h" import "C" import ( "errors" "io/ioutil" "runtime" "unsafe" ) var ( // some (effectively) constants for tests to refer to ed25519_support = C.X_ED25519_SUPPORT != 0 ) type Method *C.EVP_MD var ( SHA1_Method Method = C.X_EVP_sha1() SHA256_Method Method = C.X_EVP_sha256() SHA512_Method Method = C.X_EVP_sha512() ) // Constants for the various key types. // Mapping of name -> NID taken from openssl/evp.h const ( KeyTypeNone = NID_undef KeyTypeRSA = NID_rsaEncryption KeyTypeRSA2 = NID_rsa KeyTypeDSA = NID_dsa KeyTypeDSA1 = NID_dsa_2 KeyTypeDSA2 = NID_dsaWithSHA KeyTypeDSA3 = NID_dsaWithSHA1 KeyTypeDSA4 = NID_dsaWithSHA1_2 KeyTypeDH = NID_dhKeyAgreement KeyTypeDHX = NID_dhpublicnumber KeyTypeEC = NID_X9_62_id_ecPublicKey KeyTypeHMAC = NID_hmac KeyTypeCMAC = NID_cmac KeyTypeTLS1PRF = NID_tls1_prf KeyTypeHKDF = NID_hkdf KeyTypeX25519 = NID_X25519 KeyTypeX448 = NID_X448 KeyTypeED25519 = NID_ED25519 KeyTypeED448 = NID_ED448 ) const DefaultRSAExponent = 0x10001 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) // KeyType returns an identifier for what kind of key is represented by this // object. KeyType() NID // BaseType returns an identifier for what kind of key is represented // by this object. // Keys that share same algorithm but use different legacy formats // will have the same BaseType. // // For example, a key with a `KeyType() == KeyTypeRSA` and a key with a // `KeyType() == KeyTypeRSA2` would both have `BaseType() == KeyTypeRSA`. BaseType() NID 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 engine_ref interface{} //see comment below in EngineLoadPrivateKey } func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key } func (key *pKey) KeyType() NID { nid := C.EVP_PKEY_id(key.key) runtime.KeepAlive(key) return NID(nid) } func (key *pKey) BaseType() NID { nid := C.EVP_PKEY_base_id(key.key) runtime.KeepAlive(key) return NID(nid) } func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) { ctx := C.X_EVP_MD_CTX_new() defer C.X_EVP_MD_CTX_free(ctx) if key.KeyType() == KeyTypeED25519 { // do ED specific one-shot sign if method != nil || len(data) == 0 { return nil, errors.New("signpkcs1v15: 0-length data or non-null digest") } if 1 != C.X_EVP_DigestSignInit(ctx, nil, nil, nil, key.key) { return nil, errors.New("signpkcs1v15: failed to init signature") } // evp signatures are 64 bytes sig := make([]byte, 64, 64) var sigblen C.size_t = 64 if 1 != C.X_EVP_DigestSign(ctx, ((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data))) { return nil, errors.New("signpkcs1v15: failed to do one-shot signature") } runtime.KeepAlive(key) runtime.KeepAlive(data) return sig[:sigblen], nil } else { if 1 != C.X_EVP_SignInit(ctx, method) { return nil, errors.New("signpkcs1v15: failed to init signature") } if len(data) > 0 { if 1 != C.X_EVP_SignUpdate( ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { return nil, errors.New("signpkcs1v15: failed to update signature") } runtime.KeepAlive(data) } sig := make([]byte, C.X_EVP_PKEY_size(key.key)) var sigblen C.uint if 1 != C.X_EVP_SignFinal(ctx, ((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) { return nil, errors.New("signpkcs1v15: failed to finalize signature") } runtime.KeepAlive(key) return sig[:sigblen], nil } } func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error { ctx := C.X_EVP_MD_CTX_new() defer C.X_EVP_MD_CTX_free(ctx) if key.KeyType() == KeyTypeED25519 { // do ED specific one-shot sign if method != nil || len(data) == 0 || len(sig) == 0 { return errors.New("verifypkcs1v15: 0-length data or sig or non-null digest") } if 1 != C.X_EVP_DigestVerifyInit(ctx, nil, nil, nil, key.key) { return errors.New("verifypkcs1v15: failed to init verify") } if 1 != C.X_EVP_DigestVerify(ctx, ((*C.uchar)(unsafe.Pointer(&sig[0]))), C.size_t(len(sig)), (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data))) { return errors.New("verifypkcs1v15: failed to do one-shot verify") } runtime.KeepAlive(data) runtime.KeepAlive(sig) runtime.KeepAlive(key) return nil } else { if 1 != C.X_EVP_VerifyInit(ctx, method) { return errors.New("verifypkcs1v15: failed to init verify") } if len(data) > 0 { if 1 != C.X_EVP_VerifyUpdate( ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { return errors.New("verifypkcs1v15: failed to update verify") } } if 1 != C.X_EVP_VerifyFinal(ctx, ((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) { return errors.New("verifypkcs1v15: failed to finalize verify") } runtime.KeepAlive(data) runtime.KeepAlive(sig) runtime.KeepAlive(key) 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) // PEM_write_bio_PrivateKey_traditional will use the key-specific PKCS1 // format if one is available for that key type, otherwise it will encode // to a PKCS8 key. if int(C.X_PEM_write_bio_PrivateKey_traditional(bio, key.key, nil, nil, C.int(0), nil, nil)) != 1 { return nil, errors.New("failed dumping private key") } runtime.KeepAlive(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) if int(C.i2d_PrivateKey_bio(bio, key.key)) != 1 { return nil, errors.New("failed dumping private key der") } runtime.KeepAlive(key) 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) if int(C.PEM_write_bio_PUBKEY(bio, key.key)) != 1 { return nil, errors.New("failed dumping public key pem") } runtime.KeepAlive(key) 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) if int(C.i2d_PUBKEY_bio(bio, key.key)) != 1 { return nil, errors.New("failed dumping public key der") } runtime.KeepAlive(key) return ioutil.ReadAll(asAnyBio(bio)) } // EngineLoadPrivateKey loads a private key by id // the id is a pkcs#11 URI https://tools.ietf.org/html/rfc7512#section-2.3 // Engine comes from e.g.: e,err:=openssl.EngineById("pkcs11") func EngineLoadPrivateKey(e *Engine, id string) (PrivateKey, error) { if e == nil { return nil, errors.New("ENGINE_load_private_key cannot be called with NULL engine") } keyID := C.CString(id) defer C.free(unsafe.Pointer(keyID)) key := C.ENGINE_load_private_key(e.e, keyID, nil, nil) if key == nil { return nil, errors.New("cannot load private key, ENGINE_load_private_key error") } // engine_ref trick inspired by the work of Renato Aguiar https://github.com/renatoaguiar // it prevents the engine to be freed while we still use the key. p := &pKey{key: key, engine_ref: e} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // 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))) runtime.KeepAlive(pem_block) if bio == nil { return nil, errors.New("failed creating bio") } defer C.BIO_free(bio) key := C.PEM_read_bio_PrivateKey(bio, nil, nil, nil) if key == nil { return nil, errors.New("failed reading private key") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // LoadPrivateKeyFromPEMWithPassword loads a private key from a PEM-encoded block. func LoadPrivateKeyFromPEMWithPassword(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))) runtime.KeepAlive(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)) key := C.PEM_read_bio_PrivateKey(bio, nil, nil, unsafe.Pointer(cs)) if key == nil { return nil, errors.New("failed reading private key") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // LoadPrivateKeyFromDER loads a private key from a DER-encoded block. func LoadPrivateKeyFromDER(der_block []byte) (PrivateKey, 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))) runtime.KeepAlive(der_block) if bio == nil { return nil, errors.New("failed creating bio") } defer C.BIO_free(bio) key := C.d2i_PrivateKey_bio(bio, nil) if key == nil { return nil, errors.New("failed reading private key der") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // LoadPrivateKeyFromPEMWidthPassword loads a private key from a PEM-encoded block. // Backwards-compatible with typo func LoadPrivateKeyFromPEMWidthPassword(pem_block []byte, password string) ( PrivateKey, error) { return LoadPrivateKeyFromPEMWithPassword(pem_block, password) } // 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))) runtime.KeepAlive(pem_block) if bio == nil { return nil, errors.New("failed creating bio") } defer C.BIO_free(bio) key := C.PEM_read_bio_PUBKEY(bio, nil, nil, nil) if key == nil { return nil, errors.New("failed reading public key der") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { C.X_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))) runtime.KeepAlive(der_block) if bio == nil { return nil, errors.New("failed creating bio") } defer C.BIO_free(bio) key := C.d2i_PUBKEY_bio(bio, nil) if key == nil { return nil, errors.New("failed reading public key der") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // GenerateRSAKey generates a new RSA private key with an exponent of 65537. func GenerateRSAKey(bits int) (PrivateKey, error) { return GenerateRSAKeyWithExponent(bits, DefaultRSAExponent) } // GenerateRSAKeyWithExponent generates a new RSA private key. func GenerateRSAKeyWithExponent(bits int, exponent int) (PrivateKey, error) { exp := C.BN_new() if exp == nil { return nil, errors.New("failed to allocate BIGNUM for the exponent") } defer C.BN_free(exp) rsa := C.RSA_new() if rsa == nil { return nil, errors.New("failed to allocate RSA key") } ret := C.BN_set_word(exp, C.BN_ULONG(exponent)) if ret == 0 { C.RSA_free(rsa) return nil, errors.New("error assigning exponent to BIGNUM") } ret = C.RSA_generate_key_ex(rsa, C.int(bits), exp, nil) if ret == 0 { C.RSA_free(rsa) return nil, errors.New("failed to generate RSA key") } key := C.X_EVP_PKEY_new() if key == nil { C.RSA_free(rsa) return nil, errors.New("failed to allocate EVP_PKEY") } if C.X_EVP_PKEY_assign_charp(key, C.EVP_PKEY_RSA, (*C.char)(unsafe.Pointer(rsa))) != 1 { C.RSA_free(rsa) return nil, errors.New("failed to assign RSA key") } p := &pKey{key: key} runtime.SetFinalizer(p, func(p *pKey) { // At this point the RSA struct pointed to by the "rsa" variable // is owned by the EVP_PKEY struct and will be freed py the Finalizer C.X_EVP_PKEY_free(p.key) }) return p, nil } // GenerateECKey generates a new elliptic curve private key on the speicified // curve. func GenerateECKey(curve EllipticCurve) (PrivateKey, error) { // Create context for parameter generation paramCtx := C.EVP_PKEY_CTX_new_id(C.EVP_PKEY_EC, nil) if paramCtx == nil { return nil, errors.New("failed creating EC parameter generation context") } defer C.EVP_PKEY_CTX_free(paramCtx) // Intialize the parameter generation if int(C.EVP_PKEY_paramgen_init(paramCtx)) != 1 { return nil, errors.New("failed initializing EC parameter generation context") } // Set curve in EC parameter generation context if int(C.X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(paramCtx, C.int(curve))) != 1 { return nil, errors.New("failed setting curve in EC parameter generation context") } // Create parameter object var params *C.EVP_PKEY if int(C.EVP_PKEY_paramgen(paramCtx, ¶ms)) != 1 { return nil, errors.New("failed creating EC key generation parameters") } defer C.EVP_PKEY_free(params) // Create context for the key generation keyCtx := C.EVP_PKEY_CTX_new(params, nil) if keyCtx == nil { return nil, errors.New("failed creating EC key generation context") } defer C.EVP_PKEY_CTX_free(keyCtx) // Generate the key var privKey *C.EVP_PKEY if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 { return nil, errors.New("failed initializing EC key generation context") } if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 { return nil, errors.New("failed generating EC private key") } p := &pKey{key: privKey} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } // GenerateED25519Key generates a Ed25519 key func GenerateED25519Key() (PrivateKey, error) { // Key context keyCtx := C.EVP_PKEY_CTX_new_id(C.X_EVP_PKEY_ED25519, nil) if keyCtx == nil { return nil, errors.New("failed creating EC parameter generation context") } defer C.EVP_PKEY_CTX_free(keyCtx) // Generate the key var privKey *C.EVP_PKEY if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 { return nil, errors.New("failed initializing ED25519 key generation context") } if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 { return nil, errors.New("failed generating ED25519 private key") } p := &pKey{key: privKey} runtime.SetFinalizer(p, func(p *pKey) { C.X_EVP_PKEY_free(p.key) }) return p, nil } golang-github-mendersoftware-openssl-1.1.0/key_test.go000066400000000000000000000253261375575520400231470ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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/ecdsa" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/hex" pem_pkg "encoding/pem" "io/ioutil" "os" "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) } privateBlock, _ := pem_pkg.Decode(keyBytes) key, err = LoadPrivateKeyFromDER(privateBlock.Bytes) 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.Fatalf("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) } _, err = GenerateRSAKeyWithExponent(1024, 65537) if err != nil { t.Fatal(err) } } func TestGenerateEC(t *testing.T) { key, err := GenerateECKey(Prime256v1) if err != nil { t.Fatal(err) } _, err = key.MarshalPKIXPublicKeyPEM() if err != nil { t.Fatal(err) } _, err = key.MarshalPKCS1PrivateKeyPEM() if err != nil { t.Fatal(err) } } func TestGenerateEd25519(t *testing.T) { if !ed25519_support { t.SkipNow() } key, err := GenerateED25519Key() if err != nil { t.Fatal(err) } _, err = key.MarshalPKIXPublicKeyPEM() if err != nil { t.Fatal(err) } _, err = key.MarshalPKCS1PrivateKeyPEM() if err != nil { t.Fatal(err) } } func TestSign(t *testing.T) { key, _ := GenerateRSAKey(1024) data := []byte("the quick brown fox jumps over the lazy dog") _, err := key.SignPKCS1v15(SHA1_Method, data) if err != nil { t.Fatal(err) } _, err = key.SignPKCS1v15(SHA256_Method, data) if err != nil { t.Fatal(err) } _, err = key.SignPKCS1v15(SHA512_Method, data) if err != nil { t.Fatal(err) } } func TestSignEC(t *testing.T) { t.Parallel() key, err := GenerateECKey(Prime256v1) if err != nil { t.Fatal(err) } data := []byte("the quick brown fox jumps over the lazy dog") t.Run("sha1", func(t *testing.T) { t.Parallel() sig, err := key.SignPKCS1v15(SHA1_Method, data) if err != nil { t.Fatal(err) } err = key.VerifyPKCS1v15(SHA1_Method, data, sig) if err != nil { t.Fatal(err) } }) t.Run("sha256", func(t *testing.T) { t.Parallel() sig, err := key.SignPKCS1v15(SHA256_Method, data) if err != nil { t.Fatal(err) } err = key.VerifyPKCS1v15(SHA256_Method, data, sig) if err != nil { t.Fatal(err) } }) t.Run("sha512", func(t *testing.T) { t.Parallel() sig, err := key.SignPKCS1v15(SHA512_Method, data) if err != nil { t.Fatal(err) } err = key.VerifyPKCS1v15(SHA512_Method, data, sig) if err != nil { t.Fatal(err) } }) } func TestSignED25519(t *testing.T) { if !ed25519_support { t.SkipNow() } t.Parallel() key, err := GenerateED25519Key() if err != nil { t.Fatal(err) } data := []byte("the quick brown fox jumps over the lazy dog") t.Run("new", func(t *testing.T) { t.Parallel() sig, err := key.SignPKCS1v15(nil, data) if err != nil { t.Fatal(err) } err = key.VerifyPKCS1v15(nil, data, sig) if err != nil { t.Fatal(err) } }) } func TestMarshalEC(t *testing.T) { key, err := LoadPrivateKeyFromPEM(prime256v1KeyBytes) if err != nil { t.Fatal(err) } cert, err := LoadCertificateFromPEM(prime256v1CertBytes) if err != nil { t.Fatal(err) } privateBlock, _ := pem_pkg.Decode(prime256v1KeyBytes) key, err = LoadPrivateKeyFromDER(privateBlock.Bytes) if err != nil { t.Fatal(err) } pem, err := cert.MarshalPEM() if err != nil { t.Fatal(err) } if !bytes.Equal(pem, prime256v1CertBytes) { ioutil.WriteFile("generated", pem, 0644) ioutil.WriteFile("hardcoded", prime256v1CertBytes, 0644) t.Fatal("invalid cert pem bytes") } pem, err = key.MarshalPKCS1PrivateKeyPEM() if err != nil { t.Fatal(err) } if !bytes.Equal(pem, prime256v1KeyBytes) { ioutil.WriteFile("generated", pem, 0644) ioutil.WriteFile("hardcoded", prime256v1KeyBytes, 0644) t.Fatal("invalid private key pem bytes") } tls_cert, err := tls.X509KeyPair(prime256v1CertBytes, prime256v1KeyBytes) if err != nil { t.Fatal(err) } tls_key, ok := tls_cert.PrivateKey.(*ecdsa.PrivateKey) if !ok { t.Fatal("FASDFASDF") } _ = tls_key der, err := key.MarshalPKCS1PrivateKeyDER() if err != nil { t.Fatal(err) } tls_der, err := x509.MarshalECPrivateKey(tls_key) if err != nil { t.Fatal(err) } if !bytes.Equal(der, tls_der) { t.Fatalf("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 TestMarshalEd25519(t *testing.T) { if !ed25519_support { t.SkipNow() } key, err := LoadPrivateKeyFromPEM(ed25519KeyBytes) if err != nil { t.Fatal(err) } cert, err := LoadCertificateFromPEM(ed25519CertBytes) if err != nil { t.Fatal(err) } privateBlock, _ := pem_pkg.Decode(ed25519KeyBytes) key, err = LoadPrivateKeyFromDER(privateBlock.Bytes) if err != nil { t.Fatal(err) } pem, err := cert.MarshalPEM() if err != nil { t.Fatal(err) } if !bytes.Equal(pem, ed25519CertBytes) { ioutil.WriteFile("generated", pem, 0644) ioutil.WriteFile("hardcoded", ed25519CertBytes, 0644) t.Fatal("invalid cert pem bytes") } pem, err = key.MarshalPKCS1PrivateKeyPEM() if err != nil { t.Fatal(err) } der, err := key.MarshalPKCS1PrivateKeyDER() if err != nil { t.Fatal(err) } der, err = key.MarshalPKIXPublicKeyDER() if err != nil { t.Fatal(err) } pem, err = key.MarshalPKIXPublicKeyPEM() if err != nil { t.Fatal(err) } 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) } _, err = loaded_pubkey_from_pem.MarshalPKIXPublicKeyDER() if err != nil { t.Fatal(err) } _, err = loaded_pubkey_from_der.MarshalPKIXPublicKeyDER() if err != nil { t.Fatal(err) } } func TestEngineLoadPrivateKey(t *testing.T) { keyURI := os.Getenv("TEST_KEY_URI") if len(keyURI) < 1 { t.Skip("TEST_KEY_URI not provided, skipping test.") } e, err := EngineById("pkcs11") if err != nil { t.Fatal(err) } clientPrivateKey, err := EngineLoadPrivateKey(e, keyURI) if err != nil { t.Fatal(err) } if clientPrivateKey == nil { t.Fatal(err) } } golang-github-mendersoftware-openssl-1.1.0/mapping.go000066400000000000000000000023411375575520400227430ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "sync" "unsafe" ) // #include import "C" type mapping struct { lock sync.Mutex values map[token]unsafe.Pointer } func newMapping() *mapping { return &mapping{ values: make(map[token]unsafe.Pointer), } } type token unsafe.Pointer func (m *mapping) Add(x unsafe.Pointer) token { res := token(C.malloc(1)) m.lock.Lock() m.values[res] = x m.lock.Unlock() return res } func (m *mapping) Get(x token) unsafe.Pointer { m.lock.Lock() res := m.values[x] m.lock.Unlock() return res } func (m *mapping) Del(x token) { m.lock.Lock() delete(m.values, x) m.lock.Unlock() C.free(unsafe.Pointer(x)) } golang-github-mendersoftware-openssl-1.1.0/md4.go000066400000000000000000000042761375575520400220050ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "errors" "runtime" "unsafe" ) type MD4Hash struct { ctx *C.EVP_MD_CTX engine *Engine } func NewMD4Hash() (*MD4Hash, error) { return NewMD4HashWithEngine(nil) } func NewMD4HashWithEngine(e *Engine) (*MD4Hash, error) { hash := &MD4Hash{engine: e} hash.ctx = C.X_EVP_MD_CTX_new() if hash.ctx == nil { return nil, errors.New("openssl: md4: unable to allocate ctx") } runtime.SetFinalizer(hash, func(hash *MD4Hash) { hash.Close() }) if err := hash.Reset(); err != nil { return nil, err } return hash, nil } func (s *MD4Hash) Close() { if s.ctx != nil { C.X_EVP_MD_CTX_free(s.ctx) s.ctx = nil } } func (s *MD4Hash) Reset() error { if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md4(), engineRef(s.engine)) { return errors.New("openssl: md4: cannot init digest ctx") } runtime.KeepAlive(s) return nil } func (s *MD4Hash) Write(p []byte) (n int, err error) { if len(p) == 0 { return 0, nil } if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) { return 0, errors.New("openssl: md4: cannot update digest") } runtime.KeepAlive(s) return len(p), nil } func (s *MD4Hash) Sum() (result [16]byte, err error) { if 1 != C.X_EVP_DigestFinal_ex(s.ctx, (*C.uchar)(unsafe.Pointer(&result[0])), nil) { return result, errors.New("openssl: md4: cannot finalize ctx") } return result, s.Reset() } func MD4(data []byte) (result [16]byte, err error) { hash, err := NewMD4Hash() if err != nil { return result, err } defer hash.Close() if _, err := hash.Write(data); err != nil { return result, err } return hash.Sum() } golang-github-mendersoftware-openssl-1.1.0/md4_test.go000066400000000000000000000104771375575520400230440ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "crypto/rand" "encoding/hex" "io" "testing" ) var md4Examples = []struct{ out, in string }{ {"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, {"93875419eca14bbf961e412147839d04", "99"}, {"89b4c9a073ae963f95370a9a1e897a74", "7b89"}, {"be47aa5b399de162db079674047af65b", "803c78"}, {"6d97329845e30e79335fef1eb9d76d5e", "79b08de9"}, {"7115059e7a77e50cf722afbaad19611d", "42251df47b"}, {"468d3dfe53a140993d10cb977708c22c", "bd0ae6faa6e8"}, {"97f951156d4fe99e935b437ea5535a85", "ce511e2fd6e596"}, {"e50e5be10795a54d45aba39e6af2ecd5", "3f526ded71688ef0"}, {"c6c6d4ba2070c842f4d4388e3919a75c", "68aa2699f3fd154a5c"}, {"821fac95ab8a7443e3e0a47711e3e4ae", "133fc4081c3c9d0fe962"}, {"ac9e63ee02c6fdc097de1e2735cd1415", "f2b43f4e0e4448054e57fc"}, {"db82e7f6c26468e41b9f34082dcbf976", "ba8d2fd4323e389a23477216"}, {"bdd168bbe205e36bb852518113247a9e", "3b3b832ff6ff259ab028689bc5"}, {"c08b6b2eeab0bf3234314eb6a573cd9e", "ef0746f1fba74e018d718e74bdf1"}, {"0c2b7a7701bbe40f4668677cf3cc9bb9", "d3fd98ccbf59e8f61277ec9a668212"}, {"ce5087675d227d65de1ae02db2c8aec4", "551705b22d1b12c7056018d8a8468a7b"}, {"8130c37467524e6ab64999c4bde575a4", "d075bb0ee09f90399508e27d3059619abf"}, {"736cea235c6e67772a05d5c4c24ed5bb", "53a1880520136e99a5e42235a706ca929c5c"}, {"cdd0dc65d134efe608113ad57c053e82", "b15c56e59f525c60d563a0064866b2a8550aa8"}, {"29105f10e7570f7242e0b8f3a3514f82", "f4e6b432479abb4095cd7e4788ce9cf077acc932"}, {"33f1a70b35b51f42704aec6a01d06f8f", "6b0e95b9a09996809a1ac25142be3d46a01b78c26d"}, {"bf4a3ebf686409832d92ac0ecf70fc6e", "ee0f76cd3e233058ba311fefc089ce1d9217ab3ae229"}, {"5359d01e422ce2617f516e48b1693003", "57788a4e5514fbec6a7db6abf3f8d41cba2c843496467b"}, {"a8ad7335fa62b8f4eb40f711b2793972", "840ca6f027703fe7119bba138bfc399d8c9725854b7a36c1"}, {"5bf38c84aa17043ca1ac3b6a0d70d6f6", "a8340d43b3c2f19b963f16989b60aab83a5e90415f205fdd99"}, {"612e96a3a484716f8648874b1b3e8b16", "e66e7141838666e06e01d45dc9eaab610bf46710287b9ad6b40e"}, {"d436e950d55f25548c86ebf065a5d23e", "e8af98c8e8d86f7df0d65e225c0d48c075fafc27733d28b4a53077"}, {"b48d7af2252ec0107f5631736d756ff9", "34554eb3f2df01135aab9a157c0de8c5804c9df20b8241b83b7999e1"}, {"bcd8447e2c1de19c076c8b7a04f7469e", "af7ecf59b66eea345800d48e00e2953eb654efbf433abb27ad2c497a08"}, {"1eeb6f74cf827b50d285d6749404c5e3", "c0f89522341128dc5e5e73c8b96775d7eb3d550d9786cc88b23479e14d11"}, {"6e593341e62194911d5cc31e39835f27", "c5e4bc73821faa34adf9468441ffd97520a96cd5debda4d51edcaaf2b23fbd"}, } func TestMD4Examples(t *testing.T) { for _, ex := range md4Examples { buf, err := hex.DecodeString(ex.in) if err != nil { t.Fatal(err) } got, err := MD4(buf) if err != nil { t.Fatal(err) } if hgot := hex.EncodeToString(got[:]); hgot != ex.out { t.Fatalf("%s: %s != %s", ex.in, hgot, ex.out) } } } func TestMD4Writer(t *testing.T) { ohash, err := NewMD4Hash() if err != nil { t.Fatal(err) } for _, ex := range md4Examples { if err := ohash.Reset(); err != nil { t.Fatal(err) } buf, err := hex.DecodeString(ex.in) if err != nil { t.Fatal(err) } if _, err := ohash.Write(buf); err != nil { t.Fatal(err) } got, err := ohash.Sum() if err != nil { t.Fatal(err) } if hgot := hex.EncodeToString(got[:]); hgot != ex.out { t.Fatalf("%s: %s != %s", ex.in, hgot, ex.out) } } } type md4func func([]byte) func benchmarkMD4(b *testing.B, length int64, fn md4func) { 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 BenchmarkMD4Large_openssl(b *testing.B) { benchmarkMD4(b, 1024*1024, func(buf []byte) { MD4(buf) }) } func BenchmarkMD4Small_openssl(b *testing.B) { benchmarkMD4(b, 1, func(buf []byte) { MD4(buf) }) } golang-github-mendersoftware-openssl-1.1.0/md5.go000066400000000000000000000042761375575520400220060ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "errors" "runtime" "unsafe" ) type MD5Hash struct { ctx *C.EVP_MD_CTX engine *Engine } func NewMD5Hash() (*MD5Hash, error) { return NewMD5HashWithEngine(nil) } func NewMD5HashWithEngine(e *Engine) (*MD5Hash, error) { hash := &MD5Hash{engine: e} hash.ctx = C.X_EVP_MD_CTX_new() if hash.ctx == nil { return nil, errors.New("openssl: md5: unable to allocate ctx") } runtime.SetFinalizer(hash, func(hash *MD5Hash) { hash.Close() }) if err := hash.Reset(); err != nil { return nil, err } return hash, nil } func (s *MD5Hash) Close() { if s.ctx != nil { C.X_EVP_MD_CTX_free(s.ctx) s.ctx = nil } } func (s *MD5Hash) Reset() error { if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md5(), engineRef(s.engine)) { return errors.New("openssl: md5: cannot init digest ctx") } runtime.KeepAlive(s) return nil } func (s *MD5Hash) Write(p []byte) (n int, err error) { if len(p) == 0 { return 0, nil } if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) { return 0, errors.New("openssl: md5: cannot update digest") } runtime.KeepAlive(s) return len(p), nil } func (s *MD5Hash) Sum() (result [16]byte, err error) { if 1 != C.X_EVP_DigestFinal_ex(s.ctx, (*C.uchar)(unsafe.Pointer(&result[0])), nil) { return result, errors.New("openssl: md5: cannot finalize ctx") } return result, s.Reset() } func MD5(data []byte) (result [16]byte, err error) { hash, err := NewMD5Hash() if err != nil { return result, err } defer hash.Close() if _, err := hash.Write(data); err != nil { return result, err } return hash.Sum() } golang-github-mendersoftware-openssl-1.1.0/md5_test.go000066400000000000000000000044501375575520400230370ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "crypto/md5" "crypto/rand" "io" "testing" ) func TestMD5(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 := md5.Sum(buf) got, err := MD5(buf) if err != nil { t.Fatal(err) } if expected != got { t.Fatalf("exp:%x got:%x", expected, got) } } } func TestMD5Writer(t *testing.T) { ohash, err := NewMD5Hash() if err != nil { t.Fatal(err) } hash := md5.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 [16]byte hash.Sum(exp[:0]) got, err := ohash.Sum() if err != nil { t.Fatal(err) } if got != exp { t.Fatalf("exp:%x got:%x", exp, got) } } } type md5func func([]byte) func benchmarkMD5(b *testing.B, length int64, fn md5func) { 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 BenchmarkMD5Large_openssl(b *testing.B) { benchmarkMD5(b, 1024*1024, func(buf []byte) { MD5(buf) }) } func BenchmarkMD5Large_stdlib(b *testing.B) { benchmarkMD5(b, 1024*1024, func(buf []byte) { md5.Sum(buf) }) } func BenchmarkMD5Small_openssl(b *testing.B) { benchmarkMD5(b, 1, func(buf []byte) { MD5(buf) }) } func BenchmarkMD5Small_stdlib(b *testing.B) { benchmarkMD5(b, 1, func(buf []byte) { md5.Sum(buf) }) } golang-github-mendersoftware-openssl-1.1.0/net.go000066400000000000000000000101021375575520400220700ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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" "runtime" ) 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) runtime.KeepAlive(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) { conn, err := DialSession(network, addr, ctx, flags, nil) runtime.KeepAlive(ctx) return conn, err } // 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 } if session != nil { err := conn.setSession(session) if err != nil { c.Close() return nil, err } } if flags&DisableSNI == 0 { err = conn.SetTlsExtHostName(host) if err != nil { conn.Close() return nil, err } } 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 } golang-github-mendersoftware-openssl-1.1.0/nid.go000066400000000000000000000234561375575520400220740ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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_undef NID = 0 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 NID_X9_62_id_ecPublicKey NID = 408 NID_hmac NID = 855 NID_cmac NID = 894 NID_dhpublicnumber NID = 920 NID_tls1_prf NID = 1021 NID_hkdf NID = 1036 NID_X25519 NID = 1034 NID_X448 NID = 1035 NID_ED25519 NID = 1087 NID_ED448 NID = 1088 ) golang-github-mendersoftware-openssl-1.1.0/pem.go000066400000000000000000000016461375575520400221000ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 } golang-github-mendersoftware-openssl-1.1.0/sha1.go000066400000000000000000000044451375575520400221530ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.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} hash.ctx = C.X_EVP_MD_CTX_new() if hash.ctx == nil { return nil, errors.New("openssl: sha1: unable to allocate 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() { if s.ctx != nil { C.X_EVP_MD_CTX_free(s.ctx) s.ctx = nil } } func engineRef(e *Engine) *C.ENGINE { if e == nil { return nil } return e.e } func (s *SHA1Hash) Reset() error { if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_sha1(), engineRef(s.engine)) { return errors.New("openssl: sha1: cannot init digest ctx") } runtime.KeepAlive(s) return nil } func (s *SHA1Hash) Write(p []byte) (n int, err error) { if len(p) == 0 { return 0, nil } if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) { return 0, errors.New("openssl: sha1: cannot update digest") } runtime.KeepAlive(s) return len(p), nil } func (s *SHA1Hash) Sum() (result [20]byte, err error) { if 1 != C.X_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() } golang-github-mendersoftware-openssl-1.1.0/sha1_test.go000066400000000000000000000044741375575520400232140ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "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.Fatalf("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.Fatalf("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) }) } golang-github-mendersoftware-openssl-1.1.0/sha256.go000066400000000000000000000043671375575520400223320ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.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} hash.ctx = C.X_EVP_MD_CTX_new() if hash.ctx == nil { return nil, errors.New("openssl: sha256: unable to allocate 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() { if s.ctx != nil { C.X_EVP_MD_CTX_free(s.ctx) s.ctx = nil } } func (s *SHA256Hash) Reset() error { if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_sha256(), engineRef(s.engine)) { return errors.New("openssl: sha256: cannot init digest ctx") } runtime.KeepAlive(s) return nil } func (s *SHA256Hash) Write(p []byte) (n int, err error) { if len(p) == 0 { return 0, nil } if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) { return 0, errors.New("openssl: sha256: cannot update digest") } runtime.KeepAlive(s) return len(p), nil } func (s *SHA256Hash) Sum() (result [32]byte, err error) { if 1 != C.X_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() } golang-github-mendersoftware-openssl-1.1.0/sha256_test.go000066400000000000000000000045221375575520400233620ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 ( "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.Fatalf("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.Fatalf("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) }) } golang-github-mendersoftware-openssl-1.1.0/shim.c000066400000000000000000000445731375575520400221020ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include "_cgo_export.h" /* * Functions defined in other .c files */ extern int go_init_locks(); extern void go_thread_locking_callback(int, int, const char*, int); extern unsigned long go_thread_id_callback(); static int go_write_bio_puts(BIO *b, const char *str) { return go_write_bio_write(b, (char*)str, (int)strlen(str)); } /* ************************************************ * v1.1.1 and later implementation ************************************************ */ #if OPENSSL_VERSION_NUMBER >= 0x1010100fL const int X_ED25519_SUPPORT = 1; int X_EVP_PKEY_ED25519 = EVP_PKEY_ED25519; int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ return EVP_DigestSignInit(ctx, pctx, type, e, pkey); } int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen) { return EVP_DigestSign(ctx, sigret, siglen, tbs, tbslen); } int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ return EVP_DigestVerifyInit(ctx, pctx, type, e, pkey); } int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen){ return EVP_DigestVerify(ctx, sigret, siglen, tbs, tbslen); } #else const int X_ED25519_SUPPORT = 0; int X_EVP_PKEY_ED25519 = EVP_PKEY_NONE; int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ return 0; } int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen) { return 0; } int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ return 0; } int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen){ return 0; } #endif /* ************************************************ * v1.1.X and later implementation ************************************************ */ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL void X_BIO_set_data(BIO* bio, void* data) { BIO_set_data(bio, data); } void* X_BIO_get_data(BIO* bio) { return BIO_get_data(bio); } EVP_MD_CTX* X_EVP_MD_CTX_new() { return EVP_MD_CTX_new(); } void X_EVP_MD_CTX_free(EVP_MD_CTX* ctx) { EVP_MD_CTX_free(ctx); } static int x_bio_create(BIO *b) { BIO_set_shutdown(b, 1); BIO_set_init(b, 1); BIO_set_data(b, NULL); BIO_clear_flags(b, ~0); return 1; } static int x_bio_free(BIO *b) { return 1; } static BIO_METHOD *writeBioMethod; static BIO_METHOD *readBioMethod; BIO_METHOD* BIO_s_readBio() { return readBioMethod; } BIO_METHOD* BIO_s_writeBio() { return writeBioMethod; } int x_bio_init_methods() { writeBioMethod = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "Go Write BIO"); if (!writeBioMethod) { return 1; } if (1 != BIO_meth_set_write(writeBioMethod, (int (*)(BIO *, const char *, int))go_write_bio_write)) { return 2; } if (1 != BIO_meth_set_puts(writeBioMethod, go_write_bio_puts)) { return 3; } if (1 != BIO_meth_set_ctrl(writeBioMethod, go_write_bio_ctrl)) { return 4; } if (1 != BIO_meth_set_create(writeBioMethod, x_bio_create)) { return 5; } if (1 != BIO_meth_set_destroy(writeBioMethod, x_bio_free)) { return 6; } readBioMethod = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "Go Read BIO"); if (!readBioMethod) { return 7; } if (1 != BIO_meth_set_read(readBioMethod, go_read_bio_read)) { return 8; } if (1 != BIO_meth_set_ctrl(readBioMethod, go_read_bio_ctrl)) { return 9; } if (1 != BIO_meth_set_create(readBioMethod, x_bio_create)) { return 10; } if (1 != BIO_meth_set_destroy(readBioMethod, x_bio_free)) { return 11; } return 0; } const EVP_MD *X_EVP_dss() { return NULL; } const EVP_MD *X_EVP_dss1() { return NULL; } const EVP_MD *X_EVP_sha() { return NULL; } int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) { return EVP_CIPHER_CTX_encrypting(ctx); } int X_X509_add_ref(X509* x509) { return X509_up_ref(x509); } const ASN1_TIME *X_X509_get0_notBefore(const X509 *x) { return X509_get0_notBefore(x); } const ASN1_TIME *X_X509_get0_notAfter(const X509 *x) { return X509_get0_notAfter(x); } HMAC_CTX *X_HMAC_CTX_new(void) { return HMAC_CTX_new(); } void X_HMAC_CTX_free(HMAC_CTX *ctx) { HMAC_CTX_free(ctx); } int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { int rc = 0; rc = PEM_write_bio_PrivateKey_traditional(bio, key, enc, kstr, klen, cb, u); if (rc != 1) { return PEM_write_bio_PrivateKey(bio, key, enc, kstr, klen, cb, u); } return rc; } #endif /* ************************************************ * v1.0.X implementation ************************************************ */ #if OPENSSL_VERSION_NUMBER < 0x1010000fL static int x_bio_create(BIO *b) { b->shutdown = 1; b->init = 1; b->num = -1; b->ptr = NULL; b->flags = 0; return 1; } static int x_bio_free(BIO *b) { return 1; } static BIO_METHOD writeBioMethod = { BIO_TYPE_SOURCE_SINK, "Go Write BIO", (int (*)(BIO *, const char *, int))go_write_bio_write, NULL, go_write_bio_puts, NULL, go_write_bio_ctrl, x_bio_create, x_bio_free, NULL}; static BIO_METHOD* BIO_s_writeBio() { return &writeBioMethod; } static BIO_METHOD readBioMethod = { BIO_TYPE_SOURCE_SINK, "Go Read BIO", NULL, go_read_bio_read, NULL, NULL, go_read_bio_ctrl, x_bio_create, x_bio_free, NULL}; static BIO_METHOD* BIO_s_readBio() { return &readBioMethod; } int x_bio_init_methods() { /* statically initialized above */ return 0; } void X_BIO_set_data(BIO* bio, void* data) { bio->ptr = data; } void* X_BIO_get_data(BIO* bio) { return bio->ptr; } EVP_MD_CTX* X_EVP_MD_CTX_new() { return EVP_MD_CTX_create(); } void X_EVP_MD_CTX_free(EVP_MD_CTX* ctx) { EVP_MD_CTX_destroy(ctx); } int X_X509_add_ref(X509* x509) { CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); return 1; } const ASN1_TIME *X_X509_get0_notBefore(const X509 *x) { return x->cert_info->validity->notBefore; } const ASN1_TIME *X_X509_get0_notAfter(const X509 *x) { return x->cert_info->validity->notAfter; } const EVP_MD *X_EVP_dss() { return EVP_dss(); } const EVP_MD *X_EVP_dss1() { return EVP_dss1(); } const EVP_MD *X_EVP_sha() { return EVP_sha(); } int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) { return ctx->encrypt; } HMAC_CTX *X_HMAC_CTX_new(void) { /* v1.1.0 uses a OPENSSL_zalloc to allocate the memory which does not exist * in previous versions. malloc+memset to get the same behavior */ HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX)); if (ctx) { memset(ctx, 0, sizeof(HMAC_CTX)); HMAC_CTX_init(ctx); } return ctx; } void X_HMAC_CTX_free(HMAC_CTX *ctx) { if (ctx) { HMAC_CTX_cleanup(ctx); OPENSSL_free(ctx); } } int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { /* PEM_write_bio_PrivateKey always tries to use the PKCS8 format if it * is available, instead of using the "traditional" format as stated in the * OpenSSL man page. * i2d_PrivateKey should give us the correct DER encoding, so we'll just * use PEM_ASN1_write_bio directly to write the DER encoding with the correct * type header. */ int ppkey_id, pkey_base_id, ppkey_flags; const char *pinfo, *ppem_str; char pem_type_str[80]; // Lookup the ASN1 method information to get the pem type if (EVP_PKEY_asn1_get0_info(&ppkey_id, &pkey_base_id, &ppkey_flags, &pinfo, &ppem_str, key->ameth) != 1) { return 0; } // Set up the PEM type string if (BIO_snprintf(pem_type_str, 80, "%s PRIVATE KEY", ppem_str) <= 0) { // Failed to write out the pem type string, something is really wrong. return 0; } // Write out everything to the BIO return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_type_str, bio, key, enc, kstr, klen, cb, u); } #endif /* ************************************************ * common implementation ************************************************ */ int X_shim_init() { int rc = 0; OPENSSL_config(NULL); ENGINE_load_builtin_engines(); SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); // // Set up OPENSSL thread safety callbacks. rc = go_init_locks(); if (rc != 0) { return rc; } CRYPTO_set_locking_callback(go_thread_locking_callback); CRYPTO_set_id_callback(go_thread_id_callback); rc = x_bio_init_methods(); if (rc != 0) { return rc; } return 0; } void * X_OPENSSL_malloc(size_t size) { return OPENSSL_malloc(size); } void X_OPENSSL_free(void *ref) { OPENSSL_free(ref); } void X_SSL_set_security_level(SSL *ssl, int level) { SSL_set_security_level(ssl, level); } int X_SSL_get_security_level(SSL *ssl) { int level = 0; SSL_CTX *ctx = NULL; if (ssl == NULL) { ctx = SSL_CTX_new(TLS_method()); if (ctx == NULL) { return -1; } ssl = SSL_new(ctx); if (ssl == NULL) { SSL_CTX_free(ctx); return -1; } level = SSL_get_security_level(ssl); SSL_free(ssl); SSL_CTX_free(ctx); } else { level = SSL_get_security_level(ssl); } return level; } long X_SSL_set_options(SSL* ssl, long options) { return SSL_set_options(ssl, options); } long X_SSL_get_options(SSL* ssl) { return SSL_get_options(ssl); } long X_SSL_clear_options(SSL* ssl, long options) { return SSL_clear_options(ssl, options); } long X_SSL_set_tlsext_host_name(SSL *ssl, const char *name) { return SSL_set_tlsext_host_name(ssl, name); } const char * X_SSL_get_cipher_name(const SSL *ssl) { return SSL_get_cipher_name(ssl); } int X_SSL_session_reused(SSL *ssl) { return SSL_session_reused(ssl); } int X_SSL_new_index() { return SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); } int X_SSL_verify_cb(int ok, X509_STORE_CTX* store) { SSL* ssl = (SSL *)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); 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 go_ssl_verify_cb_thunk(p, ok, store); } const SSL_METHOD *X_SSLv23_method() { return SSLv23_method(); } const SSL_METHOD *X_SSLv3_method() { #ifndef OPENSSL_NO_SSL3_METHOD return SSLv3_method(); #else return NULL; #endif } const SSL_METHOD *X_TLSv1_method() { return TLSv1_method(); } const SSL_METHOD *X_TLSv1_1_method() { #if defined(TLS1_1_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) return TLSv1_1_method(); #else return NULL; #endif } const SSL_METHOD *X_TLSv1_2_method() { #if defined(TLS1_2_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) return TLSv1_2_method(); #else return NULL; #endif } int X_SSL_CTX_new_index() { return SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); } long X_SSL_CTX_set_options(SSL_CTX* ctx, long options) { return SSL_CTX_set_options(ctx, options); } long X_SSL_CTX_clear_options(SSL_CTX* ctx, long options) { return SSL_CTX_clear_options(ctx, options); } long X_SSL_CTX_get_options(SSL_CTX* ctx) { return SSL_CTX_get_options(ctx); } long X_SSL_CTX_set_mode(SSL_CTX* ctx, long modes) { return SSL_CTX_set_mode(ctx, modes); } long X_SSL_CTX_get_mode(SSL_CTX* ctx) { return SSL_CTX_get_mode(ctx); } long X_SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long modes) { return SSL_CTX_set_session_cache_mode(ctx, modes); } long X_SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long t) { return SSL_CTX_sess_set_cache_size(ctx, t); } long X_SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) { return SSL_CTX_sess_get_cache_size(ctx); } long X_SSL_CTX_set_timeout(SSL_CTX* ctx, long t) { return SSL_CTX_set_timeout(ctx, t); } long X_SSL_CTX_get_timeout(SSL_CTX* ctx) { return SSL_CTX_get_timeout(ctx); } long X_SSL_CTX_add_extra_chain_cert(SSL_CTX* ctx, X509 *cert) { return SSL_CTX_add_extra_chain_cert(ctx, cert); } long X_SSL_CTX_set_tmp_ecdh(SSL_CTX* ctx, EC_KEY *key) { return SSL_CTX_set_tmp_ecdh(ctx, key); } long X_SSL_CTX_set_tlsext_servername_callback( SSL_CTX* ctx, int (*cb)(SSL *con, int *ad, void *args)) { return SSL_CTX_set_tlsext_servername_callback(ctx, cb); } int X_SSL_CTX_verify_cb(int ok, X509_STORE_CTX* store) { SSL* ssl = (SSL *)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); 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 go_ssl_ctx_verify_cb_thunk(p, ok, store); } long X_SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH *dh) { return SSL_CTX_set_tmp_dh(ctx, dh); } long X_PEM_read_DHparams(SSL_CTX* ctx, DH *dh) { return SSL_CTX_set_tmp_dh(ctx, dh); } int X_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *sslctx, int (*cb)(SSL *s, unsigned char key_name[16], unsigned char iv[EVP_MAX_IV_LENGTH], EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)) { return SSL_CTX_set_tlsext_ticket_key_cb(sslctx, cb); } int X_SSL_CTX_ticket_key_cb(SSL *s, unsigned char key_name[16], unsigned char iv[EVP_MAX_IV_LENGTH], EVP_CIPHER_CTX *cctx, HMAC_CTX *hctx, int enc) { SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(s); 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 go_ticket_key_cb_thunk(p, s, key_name, iv, cctx, hctx, enc); } int X_BIO_get_flags(BIO *b) { return BIO_get_flags(b); } void X_BIO_set_flags(BIO *b, int flags) { return BIO_set_flags(b, flags); } void X_BIO_clear_flags(BIO *b, int flags) { BIO_clear_flags(b, flags); } int X_BIO_read(BIO *b, void *buf, int len) { return BIO_read(b, buf, len); } int X_BIO_write(BIO *b, const void *buf, int len) { return BIO_write(b, buf, len); } BIO *X_BIO_new_write_bio() { return BIO_new(BIO_s_writeBio()); } BIO *X_BIO_new_read_bio() { return BIO_new(BIO_s_readBio()); } const EVP_MD *X_EVP_get_digestbyname(const char *name) { return EVP_get_digestbyname(name); } const EVP_MD *X_EVP_md_null() { return EVP_md_null(); } const EVP_MD *X_EVP_md5() { return EVP_md5(); } const EVP_MD *X_EVP_md4() { return EVP_md4(); } const EVP_MD *X_EVP_ripemd160() { return EVP_ripemd160(); } const EVP_MD *X_EVP_sha224() { return EVP_sha224(); } const EVP_MD *X_EVP_sha1() { return EVP_sha1(); } const EVP_MD *X_EVP_sha256() { return EVP_sha256(); } const EVP_MD *X_EVP_sha384() { return EVP_sha384(); } const EVP_MD *X_EVP_sha512() { return EVP_sha512(); } int X_EVP_MD_size(const EVP_MD *md) { return EVP_MD_size(md); } int X_EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { return EVP_DigestInit_ex(ctx, type, impl); } int X_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt) { return EVP_DigestUpdate(ctx, d, cnt); } int X_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) { return EVP_DigestFinal_ex(ctx, md, s); } int X_EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) { return EVP_SignInit(ctx, type); } int X_EVP_SignUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt) { return EVP_SignUpdate(ctx, d, cnt); } EVP_PKEY *X_EVP_PKEY_new(void) { return EVP_PKEY_new(); } void X_EVP_PKEY_free(EVP_PKEY *pkey) { EVP_PKEY_free(pkey); } int X_EVP_PKEY_size(EVP_PKEY *pkey) { return EVP_PKEY_size(pkey); } struct rsa_st *X_EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { return EVP_PKEY_get1_RSA(pkey); } int X_EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key) { return EVP_PKEY_set1_RSA(pkey, key); } int X_EVP_PKEY_assign_charp(EVP_PKEY *pkey, int type, char *key) { return EVP_PKEY_assign(pkey, type, key); } int X_EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s, EVP_PKEY *pkey) { return EVP_SignFinal(ctx, md, s, pkey); } int X_EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) { return EVP_VerifyInit(ctx, type); } int X_EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt) { return EVP_VerifyUpdate(ctx, d, cnt); } int X_EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, unsigned int siglen, EVP_PKEY *pkey) { return EVP_VerifyFinal(ctx, sigbuf, siglen, pkey); } int X_EVP_CIPHER_block_size(EVP_CIPHER *c) { return EVP_CIPHER_block_size(c); } int X_EVP_CIPHER_key_length(EVP_CIPHER *c) { return EVP_CIPHER_key_length(c); } int X_EVP_CIPHER_iv_length(EVP_CIPHER *c) { return EVP_CIPHER_iv_length(c); } int X_EVP_CIPHER_nid(EVP_CIPHER *c) { return EVP_CIPHER_nid(c); } int X_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX *ctx) { return EVP_CIPHER_CTX_block_size(ctx); } int X_EVP_CIPHER_CTX_key_length(EVP_CIPHER_CTX *ctx) { return EVP_CIPHER_CTX_key_length(ctx); } int X_EVP_CIPHER_CTX_iv_length(EVP_CIPHER_CTX *ctx) { return EVP_CIPHER_CTX_iv_length(ctx); } void X_EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int padding) { //openssl always returns 1 for set_padding //hence return value is not checked EVP_CIPHER_CTX_set_padding(ctx, padding); } const EVP_CIPHER *X_EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx) { return EVP_CIPHER_CTX_cipher(ctx); } int X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid) { return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); } size_t X_HMAC_size(const HMAC_CTX *e) { return HMAC_size(e); } int X_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl) { return HMAC_Init_ex(ctx, key, len, md, impl); } int X_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len) { return HMAC_Update(ctx, data, len); } int X_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) { return HMAC_Final(ctx, md, len); } int X_sk_X509_num(STACK_OF(X509) *sk) { return sk_X509_num(sk); } X509 *X_sk_X509_value(STACK_OF(X509)* sk, int i) { return sk_X509_value(sk, i); } long X_X509_get_version(const X509 *x) { return X509_get_version(x); } int X_X509_set_version(X509 *x, long version) { return X509_set_version(x, version); } golang-github-mendersoftware-openssl-1.1.0/shim.h000066400000000000000000000173071375575520400221020ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include #include #include #include #include #ifndef SSL_MODE_RELEASE_BUFFERS #define SSL_MODE_RELEASE_BUFFERS 0 #endif #ifndef SSL_OP_NO_COMPRESSION #define SSL_OP_NO_COMPRESSION 0 #endif /* shim methods */ extern int X_shim_init(); /* Library methods */ extern void X_OPENSSL_free(void *ref); extern void *X_OPENSSL_malloc(size_t size); /* SSL methods */ extern void X_SSL_set_security_level(SSL *ssl, int level); extern int X_SSL_get_security_level(SSL *ssl); extern long X_SSL_set_options(SSL* ssl, long options); extern long X_SSL_get_options(SSL* ssl); extern long X_SSL_clear_options(SSL* ssl, long options); extern long X_SSL_set_tlsext_host_name(SSL *ssl, const char *name); extern const char * X_SSL_get_cipher_name(const SSL *ssl); extern int X_SSL_session_reused(SSL *ssl); extern int X_SSL_new_index(); extern const SSL_METHOD *X_SSLv23_method(); extern const SSL_METHOD *X_SSLv3_method(); extern const SSL_METHOD *X_TLSv1_method(); extern const SSL_METHOD *X_TLSv1_1_method(); extern const SSL_METHOD *X_TLSv1_2_method(); #if defined SSL_CTRL_SET_TLSEXT_HOSTNAME extern int sni_cb(SSL *ssl_conn, int *ad, void *arg); #endif extern int X_SSL_verify_cb(int ok, X509_STORE_CTX* store); /* SSL_CTX methods */ extern int X_SSL_CTX_new_index(); extern long X_SSL_CTX_set_options(SSL_CTX* ctx, long options); extern long X_SSL_CTX_clear_options(SSL_CTX* ctx, long options); extern long X_SSL_CTX_get_options(SSL_CTX* ctx); extern long X_SSL_CTX_set_mode(SSL_CTX* ctx, long modes); extern long X_SSL_CTX_get_mode(SSL_CTX* ctx); extern long X_SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long modes); extern long X_SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long t); extern long X_SSL_CTX_sess_get_cache_size(SSL_CTX* ctx); extern long X_SSL_CTX_set_timeout(SSL_CTX* ctx, long t); extern long X_SSL_CTX_get_timeout(SSL_CTX* ctx); extern long X_SSL_CTX_add_extra_chain_cert(SSL_CTX* ctx, X509 *cert); extern long X_SSL_CTX_set_tmp_ecdh(SSL_CTX* ctx, EC_KEY *key); extern long X_SSL_CTX_set_tlsext_servername_callback(SSL_CTX* ctx, int (*cb)(SSL *con, int *ad, void *args)); extern int X_SSL_CTX_verify_cb(int ok, X509_STORE_CTX* store); extern long X_SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH *dh); extern long X_PEM_read_DHparams(SSL_CTX* ctx, DH *dh); extern int X_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *sslctx, int (*cb)(SSL *s, unsigned char key_name[16], unsigned char iv[EVP_MAX_IV_LENGTH], EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)); extern int X_SSL_CTX_ticket_key_cb(SSL *s, unsigned char key_name[16], unsigned char iv[EVP_MAX_IV_LENGTH], EVP_CIPHER_CTX *cctx, HMAC_CTX *hctx, int enc); /* BIO methods */ extern int X_BIO_get_flags(BIO *b); extern void X_BIO_set_flags(BIO *bio, int flags); extern void X_BIO_clear_flags(BIO *bio, int flags); extern void X_BIO_set_data(BIO *bio, void* data); extern void *X_BIO_get_data(BIO *bio); extern int X_BIO_read(BIO *b, void *buf, int len); extern int X_BIO_write(BIO *b, const void *buf, int len); extern BIO *X_BIO_new_write_bio(); extern BIO *X_BIO_new_read_bio(); /* EVP methods */ extern const int X_ED25519_SUPPORT; extern int X_EVP_PKEY_ED25519; extern const EVP_MD *X_EVP_get_digestbyname(const char *name); extern EVP_MD_CTX *X_EVP_MD_CTX_new(); extern void X_EVP_MD_CTX_free(EVP_MD_CTX *ctx); extern const EVP_MD *X_EVP_md_null(); extern const EVP_MD *X_EVP_md5(); extern const EVP_MD *X_EVP_md4(); extern const EVP_MD *X_EVP_sha(); extern const EVP_MD *X_EVP_sha1(); extern const EVP_MD *X_EVP_dss(); extern const EVP_MD *X_EVP_dss1(); extern const EVP_MD *X_EVP_ripemd160(); extern const EVP_MD *X_EVP_sha224(); extern const EVP_MD *X_EVP_sha256(); extern const EVP_MD *X_EVP_sha384(); extern const EVP_MD *X_EVP_sha512(); extern int X_EVP_MD_size(const EVP_MD *md); extern int X_EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl); extern int X_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt); extern int X_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s); extern int X_EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type); extern int X_EVP_SignUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); extern int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey); extern int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen); extern EVP_PKEY *X_EVP_PKEY_new(void); extern void X_EVP_PKEY_free(EVP_PKEY *pkey); extern int X_EVP_PKEY_size(EVP_PKEY *pkey); extern struct rsa_st *X_EVP_PKEY_get1_RSA(EVP_PKEY *pkey); extern int X_EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); extern int X_EVP_PKEY_assign_charp(EVP_PKEY *pkey, int type, char *key); extern int X_EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s, EVP_PKEY *pkey); extern int X_EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type); extern int X_EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); extern int X_EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, unsigned int siglen, EVP_PKEY *pkey); extern int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey); extern int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen); extern int X_EVP_CIPHER_block_size(EVP_CIPHER *c); extern int X_EVP_CIPHER_key_length(EVP_CIPHER *c); extern int X_EVP_CIPHER_iv_length(EVP_CIPHER *c); extern int X_EVP_CIPHER_nid(EVP_CIPHER *c); extern int X_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX *ctx); extern int X_EVP_CIPHER_CTX_key_length(EVP_CIPHER_CTX *ctx); extern int X_EVP_CIPHER_CTX_iv_length(EVP_CIPHER_CTX *ctx); extern void X_EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int padding); extern const EVP_CIPHER *X_EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx); extern int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx); extern int X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid); /* HMAC methods */ extern size_t X_HMAC_size(const HMAC_CTX *e); extern HMAC_CTX *X_HMAC_CTX_new(void); extern void X_HMAC_CTX_free(HMAC_CTX *ctx); extern int X_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl); extern int X_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); extern int X_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); /* X509 methods */ extern int X_X509_add_ref(X509* x509); extern const ASN1_TIME *X_X509_get0_notBefore(const X509 *x); extern const ASN1_TIME *X_X509_get0_notAfter(const X509 *x); extern int X_sk_X509_num(STACK_OF(X509) *sk); extern X509 *X_sk_X509_value(STACK_OF(X509)* sk, int i); extern long X_X509_get_version(const X509 *x); extern int X_X509_set_version(X509 *x, long version); /* PEM methods */ extern int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u); golang-github-mendersoftware-openssl-1.1.0/sni.c000066400000000000000000000015331375575520400217200ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 #include "_cgo_export.h" #include 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); } golang-github-mendersoftware-openssl-1.1.0/ssl.go000066400000000000000000000137261375575520400221220ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "os" "runtime" "unsafe" ) type SSLTLSExtErr int const ( SSLTLSExtErrOK SSLTLSExtErr = C.SSL_TLSEXT_ERR_OK SSLTLSExtErrAlertWarning SSLTLSExtErr = C.SSL_TLSEXT_ERR_ALERT_WARNING SSLTLSEXTErrAlertFatal SSLTLSExtErr = C.SSL_TLSEXT_ERR_ALERT_FATAL SSLTLSEXTErrNoAck SSLTLSExtErr = C.SSL_TLSEXT_ERR_NOACK ) var ( ssl_idx = C.X_SSL_new_index() ) //export get_ssl_idx func get_ssl_idx() C.int { return ssl_idx } type SSL struct { ssl *C.SSL verify_cb VerifyCallback } //export go_ssl_verify_cb_thunk func go_ssl_verify_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int { defer func() { if err := recover(); err != nil { 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 } // Wrapper around SSL_get_servername. Returns server name according to rfc6066 // http://tools.ietf.org/html/rfc6066. func (s *SSL) GetServername() string { ret := C.GoString(C.SSL_get_servername(s.ssl, C.TLSEXT_NAMETYPE_host_name)) runtime.KeepAlive(s) return ret } // same as GetSecurityLevel but for use without pointer to SSL func GetSecurityLevelGlobal() int { return int(C.X_SSL_get_security_level(nil)) } // GetSecurityLevel gets the SSL security level. See // https://www.openssl.org/docs/ssl/SSL_get_security_level.html func (s *SSL) GetSecurityLevel() int { ret := int(C.X_SSL_get_security_level(s.ssl)) runtime.KeepAlive(s) return ret } // SetSecurityLevel sets the SSL security level. See // https://www.openssl.org/docs/ssl/SSL_set_security_level.html func (s *SSL) SetSecurityLevel(level int) { C.X_SSL_set_security_level(s.ssl, C.int(level)) runtime.KeepAlive(s) } // GetOptions returns SSL options. See // https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html func (s *SSL) GetOptions() Options { ret := Options(C.X_SSL_get_options(s.ssl)) runtime.KeepAlive(s) return ret } // SetOptions sets SSL options. See // https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html func (s *SSL) SetOptions(options Options) Options { ret := Options(C.X_SSL_set_options(s.ssl, C.long(options))) runtime.KeepAlive(s) return ret } // ClearOptions clear SSL options. See // https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html func (s *SSL) ClearOptions(options Options) Options { ret := Options(C.X_SSL_clear_options(s.ssl, C.long(options))) runtime.KeepAlive(s) return ret } // 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.X_SSL_verify_cb)) } else { C.SSL_set_verify(s.ssl, C.int(options), nil) } runtime.KeepAlive(s) } // 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) runtime.KeepAlive(s) } // 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(), verify_cb) runtime.KeepAlive(s) } // 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 { ret := VerifyOptions(C.SSL_get_verify_mode(s.ssl)) runtime.KeepAlive(s) return ret } // 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)) runtime.KeepAlive(s) } // 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 { ret := int(C.SSL_get_verify_depth(s.ssl)) runtime.KeepAlive(s) return ret } // SetSSLCtx changes context to new one. Useful for Server Name Indication (SNI) // rfc6066 http://tools.ietf.org/html/rfc6066. See // http://stackoverflow.com/questions/22373332/serving-multiple-domains-in-one-box-with-sni func (s *SSL) SetSSLCtx(ctx *Ctx) { /* * SSL_set_SSL_CTX() only changes certs as of 1.0.0d * adjust other things we care about */ C.SSL_set_SSL_CTX(s.ssl, ctx.ctx) runtime.KeepAlive(s) runtime.KeepAlive(ctx) } //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 { 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. //go vet complains here: //183:42: possibly passing Go type with embedded pointer to C u := unsafe.Pointer(s) C.SSL_set_ex_data(s.ssl, get_ssl_idx(), u) // Note: this is ctx.sni_cb, not C.sni_cb return C.int(sni_cb(s)) } golang-github-mendersoftware-openssl-1.1.0/ssl_test.go000066400000000000000000000427231375575520400231600ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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/mendersoftware/openssl/utils" ) var ( certBytes = []byte(`-----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIUC/bE9dNi+LCLwNNh2g1jPc7GdNkwDQYJKoZIhvcNAQEN BQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE CgwTRGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yMDA4MjcwODU2MTVaFw0zMDA4MjUw ODU2MTVaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAa BgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDdf3icNvFsrlrnNLi8SocscqlSbFq+pEvmhcSoqgDLqebnqu8L d73HJJ74MGXEgRX8xZT5FinOML31CR6t9E/j3dqV6p+GfdlFLe3IqtC0/bPVnCDB irBygBI4uCrMq+1VhAxPWclrDo7l9QRYbsExH9lfn+RyvxeNMZiOASasvVZNncY8 E9usBGRdH17EfDL/TPwXqWOLyxSN5o54GTztjjy9w9CGQP7jcCueKYyQJQCtEmnw c6P/q6/EPv5R6drBkX6loAPtmCUAkHqxkWOJrRq/v7PwzRYhfY+ZpVHGc7WEkDnL zRiUypr1C9oxvLKS10etZEIwEdKyOkSg2fdPAgMBAAGjUzBRMB0GA1UdDgQWBBSj 8Z6d2TqacRP4allwQM1FYgltPzAfBgNVHSMEGDAWgBSj8Z6d2TqacRP4allwQM1F YgltPzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQBjRvQDpvzJ ClK+lsvieWLiKGg6DVCJkHQd+YpJBzjUBgSPF7Ylcl6IK+H7vDa7EByDM8kdChkd k3JY5xd1kVTuatQdgQMw0BwfTszqEZACPRdUHX+VwR8RvGBSlpUABUL9pn7/RyOH JptXv9TRj1QNz7WFMrxAYtkkjrPqJoF7ncg+84tK5n9X6TBH3eT0cbUq44llt0F4 qml1IRNbDrfvjiHLGCn0TcgEP8sz3EyDpTaBCb2xBvpntpW86okiadxnlV4dDcoX sYii9I00yblzzgVBZsgErcDm+qozoptRQfHMIzgqbF7FWN/JMM5SaRwWiOMN4RPt wL7GM5QjNFog -----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----- `) prime256v1KeyBytes = []byte(`-----BEGIN EC PRIVATE KEY----- MHcCAQEEIB/XL0zZSsAu+IQF1AI/nRneabb2S126WFlvvhzmYr1KoAoGCCqGSM49 AwEHoUQDQgAESSFGWwF6W1hoatKGPPorh4+ipyk0FqpiWdiH+4jIiU39qtOeZGSh 1QgSbzfdHxvoYI0FXM+mqE7wec0kIvrrHw== -----END EC PRIVATE KEY----- `) prime256v1CertBytes = []byte(`-----BEGIN CERTIFICATE----- MIIChTCCAiqgAwIBAgIJAOQII2LQl4uxMAoGCCqGSM49BAMCMIGcMQswCQYDVQQG EwJVUzEPMA0GA1UECAwGS2Fuc2FzMRAwDgYDVQQHDAdOb3doZXJlMR8wHQYDVQQK DBZGYWtlIENlcnRpZmljYXRlcywgSW5jMUkwRwYDVQQDDEBhMWJkZDVmZjg5ZjQy N2IwZmNiOTdlNDMyZTY5Nzg2NjI2ODJhMWUyNzM4MDhkODE0ZWJiZjY4ODBlYzA3 NDljMB4XDTE3MTIxNTIwNDU1MVoXDTI3MTIxMzIwNDU1MVowgZwxCzAJBgNVBAYT AlVTMQ8wDQYDVQQIDAZLYW5zYXMxEDAOBgNVBAcMB05vd2hlcmUxHzAdBgNVBAoM FkZha2UgQ2VydGlmaWNhdGVzLCBJbmMxSTBHBgNVBAMMQGExYmRkNWZmODlmNDI3 YjBmY2I5N2U0MzJlNjk3ODY2MjY4MmExZTI3MzgwOGQ4MTRlYmJmNjg4MGVjMDc0 OWMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARJIUZbAXpbWGhq0oY8+iuHj6Kn KTQWqmJZ2If7iMiJTf2q055kZKHVCBJvN90fG+hgjQVcz6aoTvB5zSQi+usfo1Mw UTAdBgNVHQ4EFgQUfRYAFhlGM1wzvusyGrm26Vrbqm4wHwYDVR0jBBgwFoAUfRYA FhlGM1wzvusyGrm26Vrbqm4wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJ ADBGAiEA6PWNjm4B6zs3Wcha9qyDdfo1ILhHfk9rZEAGrnfyc2UCIQD1IDVJUkI4 J/QVoOtP5DOdRPs/3XFy0Bk0qH+Uj5D7LQ== -----END CERTIFICATE----- `) ed25519CertBytes = []byte(`-----BEGIN CERTIFICATE----- MIIBIzCB1gIUd0UUPX+qHrSKSVN9V/A3F1Eeti4wBQYDK2VwMDYxCzAJBgNVBAYT AnVzMQ0wCwYDVQQKDARDU0NPMRgwFgYDVQQDDA9lZDI1NTE5X3Jvb3RfY2EwHhcN MTgwODE3MDMzNzQ4WhcNMjgwODE0MDMzNzQ4WjAzMQswCQYDVQQGEwJ1czENMAsG A1UECgwEQ1NDTzEVMBMGA1UEAwwMZWQyNTUxOV9sZWFmMCowBQYDK2VwAyEAKZZJ zzlBcpjdbvzV0BRoaSiJKxbU6GnFeAELA0cHWR0wBQYDK2VwA0EAbfUJ7L7v3GDq Gv7R90wQ/OKAc+o0q9eOrD6KRYDBhvlnMKqTMRVucnHXfrd5Rhmf4yHTvFTOhwmO t/hpmISAAA== -----END CERTIFICATE----- `) ed25519KeyBytes = []byte(`-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIL3QVwyuusKuLgZwZn356UHk9u1REGHbNTLtFMPKNQSb -----END 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") } }() 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, _ := ioutil.ReadAll(sslconn2) if !bytes.Equal(data, []byte("hello")) { t.Fatal(`bytes don't match: "` + string(data) + `" != "hello"`, ) } }() 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 TestEnsureSecLevel2(t *testing.T) { sec_level := GetSecurityLevelGlobal() if sec_level != 2 { t.Fatalf("Expected SECLEVEL 2, got %d", sec_level) } } 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) }) } golang-github-mendersoftware-openssl-1.1.0/tickets.go000066400000000000000000000133331375575520400227610ustar00rootroot00000000000000// Copyright (C) 2017. See AUTHORS. // // 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 // #include "shim.h" import "C" import ( "os" "unsafe" ) const ( KeyNameSize = 16 ) // TicketCipherCtx describes the cipher that will be used by the ticket store // for encrypting the tickets. Engine may be nil if no engine is desired. type TicketCipherCtx struct { Cipher *Cipher Engine *Engine } // TicketDigestCtx describes the digest that will be used by the ticket store // to authenticate the data. Engine may be nil if no engine is desired. type TicketDigestCtx struct { Digest *Digest Engine *Engine } // TicketName is an identifier for the key material for a ticket. type TicketName [KeyNameSize]byte // TicketKey is the key material for a ticket. If this is lost, forward secrecy // is lost as it allows decrypting TLS sessions retroactively. type TicketKey struct { Name TicketName CipherKey []byte HMACKey []byte IV []byte } // TicketKeyManager is a manager for TicketKeys. It allows one to control the // lifetime of tickets, causing renewals and expirations for keys that are // created. Calls to the manager are serialized. type TicketKeyManager interface { // New should create a brand new TicketKey with a new name. New() *TicketKey // Current should return a key that is still valid. Current() *TicketKey // Lookup should return a key with the given name, or nil if no name // exists. Lookup(name TicketName) *TicketKey // Expired should return if the key with the given name is expired and // should not be used any more. Expired(name TicketName) bool // ShouldRenew should return if the key is still ok to use for the current // session, but we should send a new key for the client. ShouldRenew(name TicketName) bool } // TicketStore descibes the encryption and authentication methods the tickets // will use along with a key manager for generating and keeping track of the // secrets. type TicketStore struct { CipherCtx TicketCipherCtx DigestCtx TicketDigestCtx Keys TicketKeyManager } func (t *TicketStore) cipherEngine() *C.ENGINE { if t.CipherCtx.Engine == nil { return nil } return t.CipherCtx.Engine.e } func (t *TicketStore) digestEngine() *C.ENGINE { if t.DigestCtx.Engine == nil { return nil } return t.DigestCtx.Engine.e } const ( // instruct to do a handshake ticket_resp_requireHandshake = 0 // crypto context is set up correctly ticket_resp_sessionOk = 1 // crypto context is ok, but the ticket should be reissued ticket_resp_renewSession = 2 // we had a problem that shouldn't fall back to doing a handshake ticket_resp_error = -1 // asked to create session crypto context ticket_req_newSession = 1 // asked to load crypto context for a previous session ticket_req_lookupSession = 0 ) //export go_ticket_key_cb_thunk func go_ticket_key_cb_thunk(p unsafe.Pointer, s *C.SSL, key_name *C.uchar, iv *C.uchar, cctx *C.EVP_CIPHER_CTX, hctx *C.HMAC_CTX, enc C.int) C.int { // no panic's allowed. it's super hard to guarantee any state at this point // so just abort everything. defer func() { if err := recover(); err != nil { os.Exit(1) } }() ctx := (*Ctx)(p) store := ctx.ticket_store if store == nil { // TODO(jeff): should this be an error condition? it doesn't make sense // to be called if we don't have a store I believe, but that's probably // not worth aborting the handshake which is what I believe returning // an error would do. return ticket_resp_requireHandshake } ctx.ticket_store_mu.Lock() defer ctx.ticket_store_mu.Unlock() switch enc { case ticket_req_newSession: key := store.Keys.Current() if key == nil { key = store.Keys.New() if key == nil { return ticket_resp_requireHandshake } } C.memcpy( unsafe.Pointer(key_name), unsafe.Pointer(&key.Name[0]), KeyNameSize) C.EVP_EncryptInit_ex( cctx, store.CipherCtx.Cipher.ptr, store.cipherEngine(), (*C.uchar)(&key.CipherKey[0]), (*C.uchar)(&key.IV[0])) C.HMAC_Init_ex( hctx, unsafe.Pointer(&key.HMACKey[0]), C.int(len(key.HMACKey)), store.DigestCtx.Digest.ptr, store.digestEngine()) return ticket_resp_sessionOk case ticket_req_lookupSession: var name TicketName C.memcpy( unsafe.Pointer(&name[0]), unsafe.Pointer(key_name), KeyNameSize) key := store.Keys.Lookup(name) if key == nil { return ticket_resp_requireHandshake } if store.Keys.Expired(name) { return ticket_resp_requireHandshake } C.EVP_DecryptInit_ex( cctx, store.CipherCtx.Cipher.ptr, store.cipherEngine(), (*C.uchar)(&key.CipherKey[0]), (*C.uchar)(&key.IV[0])) C.HMAC_Init_ex( hctx, unsafe.Pointer(&key.HMACKey[0]), C.int(len(key.HMACKey)), store.DigestCtx.Digest.ptr, store.digestEngine()) if store.Keys.ShouldRenew(name) { return ticket_resp_renewSession } return ticket_resp_sessionOk default: return ticket_resp_error } } // SetTicketStore sets the ticket store for the context so that clients can do // ticket based session resumption. If the store is nil, the func (c *Ctx) SetTicketStore(store *TicketStore) { c.ticket_store = store if store == nil { C.X_SSL_CTX_set_tlsext_ticket_key_cb(c.ctx, nil) } else { C.X_SSL_CTX_set_tlsext_ticket_key_cb(c.ctx, (*[0]byte)(C.X_SSL_CTX_ticket_key_cb)) } } golang-github-mendersoftware-openssl-1.1.0/utils/000077500000000000000000000000001375575520400221215ustar00rootroot00000000000000golang-github-mendersoftware-openssl-1.1.0/utils/errors.go000066400000000000000000000026411375575520400237670ustar00rootroot00000000000000// 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")) } golang-github-mendersoftware-openssl-1.1.0/utils/future.go000066400000000000000000000041221375575520400237610ustar00rootroot00000000000000// 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() }