mirror of
https://github.com/libp2p/go-openssl.git
synced 2025-01-30 05:20:08 +08:00
add SNI (RFC 6066)
This commit is contained in:
parent
e16f9ab26d
commit
149d3f13bd
41
ctx.go
41
ctx.go
@ -30,6 +30,10 @@ static long SSL_CTX_clear_options_not_a_macro(SSL_CTX* ctx, long options) {
|
||||
return SSL_CTX_clear_options(ctx, options);
|
||||
}
|
||||
|
||||
static long SSL_CTX_get_options_not_a_macro(SSL_CTX* ctx) {
|
||||
return SSL_CTX_get_options(ctx);
|
||||
}
|
||||
|
||||
static long SSL_CTX_set_mode_not_a_macro(SSL_CTX* ctx, long modes) {
|
||||
return SSL_CTX_set_mode(ctx, modes);
|
||||
}
|
||||
@ -70,6 +74,11 @@ static long SSL_CTX_set_tmp_ecdh_not_a_macro(SSL_CTX* ctx, EC_KEY *key) {
|
||||
return SSL_CTX_set_tmp_ecdh(ctx, key);
|
||||
}
|
||||
|
||||
static long SSL_CTX_set_tlsext_servername_callback_not_a_macro(
|
||||
SSL_CTX* ctx, int (*cb)(SSL *con, int *ad, void *args)) {
|
||||
return SSL_CTX_set_tlsext_servername_callback(ctx, cb);
|
||||
}
|
||||
|
||||
#ifndef SSL_MODE_RELEASE_BUFFERS
|
||||
#define SSL_MODE_RELEASE_BUFFERS 0
|
||||
#endif
|
||||
@ -94,6 +103,10 @@ static const SSL_METHOD *OUR_TLSv1_2_method() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
extern int sni_cb(SSL *ssl_conn, int *ad, void *arg);
|
||||
#endif
|
||||
|
||||
extern int verify_cb(int ok, X509_STORE_CTX* store);
|
||||
*/
|
||||
import "C"
|
||||
@ -123,6 +136,7 @@ type Ctx struct {
|
||||
chain []*Certificate
|
||||
key PrivateKey
|
||||
verify_cb VerifyCallback
|
||||
sni_cb TLSExtServernameCallback
|
||||
|
||||
ticket_store_mu sync.Mutex
|
||||
ticket_store *TicketStore
|
||||
@ -462,6 +476,12 @@ func (c *Ctx) ClearOptions(options Options) Options {
|
||||
c.ctx, C.long(options)))
|
||||
}
|
||||
|
||||
// GetOptions returns context options. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
|
||||
func (c *Ctx) GetOptions() Options {
|
||||
return Options(C.SSL_CTX_get_options_not_a_macro(c.ctx))
|
||||
}
|
||||
|
||||
type Modes int
|
||||
|
||||
const (
|
||||
@ -532,6 +552,10 @@ func (c *Ctx) SetVerifyCallback(verify_cb VerifyCallback) {
|
||||
c.SetVerify(c.VerifyMode(), verify_cb)
|
||||
}
|
||||
|
||||
func (c *Ctx) GetVerifyCallback() VerifyCallback {
|
||||
return c.verify_cb
|
||||
}
|
||||
|
||||
func (c *Ctx) VerifyMode() VerifyOptions {
|
||||
return VerifyOptions(C.SSL_CTX_get_verify_mode(c.ctx))
|
||||
}
|
||||
@ -543,6 +567,23 @@ func (c *Ctx) SetVerifyDepth(depth int) {
|
||||
C.SSL_CTX_set_verify_depth(c.ctx, C.int(depth))
|
||||
}
|
||||
|
||||
// GetVerifyDepth controls how many certificates deep the certificate
|
||||
// verification logic is willing to follow a certificate chain. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (c *Ctx) GetVerifyDepth() int {
|
||||
return int(C.SSL_CTX_get_verify_depth(c.ctx))
|
||||
}
|
||||
|
||||
type TLSExtServernameCallback func(ssl *SSL) SSLTLSExtErr
|
||||
|
||||
// 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.SSL_CTX_set_tlsext_servername_callback_not_a_macro(c.ctx, (*[0]byte)(C.sni_cb))
|
||||
}
|
||||
|
||||
func (c *Ctx) SetSessionId(session_id []byte) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
23
sni.c
Normal file
23
sni.c
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2014 Space Monkey, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include "_cgo_export.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int sni_cb(SSL *con, int *ad, void *arg) {
|
||||
SSL_CTX* ssl_ctx = ssl_ctx = SSL_get_SSL_CTX(con);
|
||||
void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx());
|
||||
return sni_cb_thunk(p, con, ad, arg);
|
||||
}
|
23
sni_test.go
Normal file
23
sni_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2014 Space Monkey, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package openssl
|
||||
|
||||
import "fmt"
|
||||
|
||||
// We can implemant SNI rfc6066 (http://tools.ietf.org/html/rfc6066) on the server side using foolowing callback.
|
||||
// You should implement context storage (tlsCtxStorage) by your self.
|
||||
func ExampleSetTLSExtServernameCallback() {
|
||||
fmt.Println("Hello")
|
||||
}
|
191
ssl.go
Normal file
191
ssl.go
Normal file
@ -0,0 +1,191 @@
|
||||
// Copyright (C) 2014 Space Monkey, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build cgo
|
||||
|
||||
package openssl
|
||||
|
||||
/*
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
static long SSL_set_options_not_a_macro(SSL* ssl, long options) {
|
||||
return SSL_set_options(ssl, options);
|
||||
}
|
||||
|
||||
static long SSL_get_options_not_a_macro(SSL* ssl) {
|
||||
return SSL_get_options(ssl);
|
||||
}
|
||||
|
||||
static long SSL_clear_options_not_a_macro(SSL* ssl, long options) {
|
||||
return SSL_clear_options(ssl, options);
|
||||
}
|
||||
|
||||
extern int verify_ssl_cb(int ok, X509_STORE_CTX* store);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type SSLTLSExtErr int
|
||||
|
||||
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.SSL_get_ex_new_index(0, nil, nil, nil, nil)
|
||||
)
|
||||
|
||||
//export get_ssl_idx
|
||||
func get_ssl_idx() C.int {
|
||||
return ssl_idx
|
||||
}
|
||||
|
||||
type SSL struct {
|
||||
ssl *C.SSL
|
||||
verify_cb VerifyCallback
|
||||
}
|
||||
|
||||
//export verify_ssl_cb_thunk
|
||||
func verify_ssl_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger.Critf("openssl: verify callback panic'd: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
verify_cb := (*SSL)(p).verify_cb
|
||||
// set up defaults just in case verify_cb is nil
|
||||
if verify_cb != nil {
|
||||
store := &CertificateStoreCtx{ctx: ctx}
|
||||
if verify_cb(ok == 1, store) {
|
||||
ok = 1
|
||||
} else {
|
||||
ok = 0
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// Wrapper around SSL_get_servername. Returns server name according to rfc6066
|
||||
// http://tools.ietf.org/html/rfc6066.
|
||||
func (s *SSL) GetServername() string {
|
||||
return C.GoString(C.SSL_get_servername(s.ssl, C.TLSEXT_NAMETYPE_host_name))
|
||||
}
|
||||
|
||||
// GetOptions returns SSL options. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
|
||||
func (s *SSL) GetOptions() Options {
|
||||
return Options(C.SSL_get_options_not_a_macro(s.ssl))
|
||||
}
|
||||
|
||||
// SetOptions sets SSL options. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
|
||||
func (s *SSL) SetOptions(options Options) Options {
|
||||
return Options(C.SSL_set_options_not_a_macro(s.ssl, C.long(options)))
|
||||
}
|
||||
|
||||
// ClearOptions clear SSL options. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
|
||||
func (s *SSL) ClearOptions(options Options) Options {
|
||||
return Options(C.SSL_clear_options_not_a_macro(s.ssl, C.long(options)))
|
||||
}
|
||||
|
||||
// SetVerify controls peer verification settings. See
|
||||
// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) SetVerify(options VerifyOptions, verify_cb VerifyCallback) {
|
||||
s.verify_cb = verify_cb
|
||||
if verify_cb != nil {
|
||||
C.SSL_set_verify(s.ssl, C.int(options), (*[0]byte)(C.verify_ssl_cb))
|
||||
} else {
|
||||
C.SSL_set_verify(s.ssl, C.int(options), nil)
|
||||
}
|
||||
}
|
||||
|
||||
// SetVerifyMode controls peer verification setting. See
|
||||
// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) SetVerifyMode(options VerifyOptions) {
|
||||
s.SetVerify(options, s.verify_cb)
|
||||
}
|
||||
|
||||
// SetVerifyCallback controls peer verification setting. See
|
||||
// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) SetVerifyCallback(verify_cb VerifyCallback) {
|
||||
s.SetVerify(s.VerifyMode(), s.verify_cb)
|
||||
}
|
||||
|
||||
// GetVerifyCallback returns callback function. See
|
||||
// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) GetVerifyCallback() VerifyCallback {
|
||||
return s.verify_cb
|
||||
}
|
||||
|
||||
// VerifyMode returns peer verification setting. See
|
||||
// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) VerifyMode() VerifyOptions {
|
||||
return VerifyOptions(C.SSL_get_verify_mode(s.ssl))
|
||||
}
|
||||
|
||||
// SetVerifyDepth controls how many certificates deep the certificate
|
||||
// verification logic is willing to follow a certificate chain. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) SetVerifyDepth(depth int) {
|
||||
C.SSL_set_verify_depth(s.ssl, C.int(depth))
|
||||
}
|
||||
|
||||
// GetVerifyDepth controls how many certificates deep the certificate
|
||||
// verification logic is willing to follow a certificate chain. See
|
||||
// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
|
||||
func (s *SSL) GetVerifyDepth() int {
|
||||
return int(C.SSL_get_verify_depth(s.ssl))
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
//export sni_cb_thunk
|
||||
func sni_cb_thunk(p unsafe.Pointer, con *C.SSL, ad unsafe.Pointer, arg unsafe.Pointer) C.int {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger.Critf("openssl: verify callback sni panic'd: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
sni_cb := (*Ctx)(p).sni_cb
|
||||
|
||||
s := &SSL{ssl: con}
|
||||
// This attaches a pointer to our SSL struct into the SNI callback.
|
||||
C.SSL_set_ex_data(s.ssl, get_ssl_idx(), unsafe.Pointer(s))
|
||||
|
||||
// Note: this is ctx.sni_cb, not C.sni_cb
|
||||
return C.int(sni_cb(s))
|
||||
}
|
7
verify.c
7
verify.c
@ -22,3 +22,10 @@ int verify_cb(int ok, X509_STORE_CTX* store) {
|
||||
// get the pointer to the go Ctx object and pass it back into the thunk
|
||||
return verify_cb_thunk(p, ok, store);
|
||||
}
|
||||
|
||||
int verify_ssl_cb(int ok, X509_STORE_CTX* store) {
|
||||
SSL* ssl = (SSL *)X509_STORE_CTX_get_app_data(store);
|
||||
void* p = SSL_get_ex_data(ssl, get_ssl_idx());
|
||||
// get the pointer to the go Ctx object and pass it back into the thunk
|
||||
return verify_ssl_cb_thunk(p, ok, store);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user