From 3b86b4289698d744c920509006fb1d943ba1ecad Mon Sep 17 00:00:00 2001 From: Jeff Wendling Date: Wed, 5 Sep 2018 07:33:13 -0600 Subject: [PATCH] add support for get/set x509 version closes #61 --- cert.go | 24 ++++++++++++++++++++++++ cert_test.go | 33 +++++++++++++++++++++++++++++---- shim.c | 10 +++++++++- shim.h | 2 ++ sni_test.go | 23 ----------------------- 5 files changed, 64 insertions(+), 28 deletions(-) delete mode 100644 sni_test.go diff --git a/cert.go b/cert.go index d50c53f..3b424a6 100644 --- a/cert.go +++ b/cert.go @@ -43,6 +43,16 @@ const ( 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 @@ -388,3 +398,17 @@ func (c *Certificate) GetSerialNumberHex() (serial string) { C.X_OPENSSL_free(unsafe.Pointer(hex)) return } + +// GetVersion returns the X509 version of the certificate. +func (c *Certificate) GetVersion() X509_Version { + return X509_Version(C.X_X509_get_version(c.x)) +} + +// 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") + } + return nil +} diff --git a/cert_test.go b/cert_test.go index 9608326..45107a0 100644 --- a/cert_test.go +++ b/cert_test.go @@ -21,7 +21,7 @@ import ( ) func TestCertGenerate(t *testing.T) { - key, err := GenerateRSAKey(2048) + key, err := GenerateRSAKey(768) if err != nil { t.Fatal(err) } @@ -43,7 +43,7 @@ func TestCertGenerate(t *testing.T) { } func TestCAGenerate(t *testing.T) { - cakey, err := GenerateRSAKey(2048) + cakey, err := GenerateRSAKey(768) if err != nil { t.Fatal(err) } @@ -70,7 +70,7 @@ func TestCAGenerate(t *testing.T) { if err := ca.Sign(cakey, EVP_SHA256); err != nil { t.Fatal(err) } - key, err := GenerateRSAKey(2048) + key, err := GenerateRSAKey(768) if err != nil { t.Fatal(err) } @@ -102,7 +102,7 @@ func TestCAGenerate(t *testing.T) { } func TestCertGetNameEntry(t *testing.T) { - key, err := GenerateRSAKey(2048) + key, err := GenerateRSAKey(768) if err != nil { t.Fatal(err) } @@ -137,3 +137,28 @@ func TestCertGetNameEntry(t *testing.T) { 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) + } +} diff --git a/shim.c b/shim.c index edf440c..755eb02 100644 --- a/shim.c +++ b/shim.c @@ -666,7 +666,7 @@ int X_EVP_CIPHER_CTX_iv_length(EVP_CIPHER_CTX *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 + //hence return value is not checked EVP_CIPHER_CTX_set_padding(ctx, padding); } @@ -701,3 +701,11 @@ int X_sk_X509_num(STACK_OF(X509) *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); +} diff --git a/shim.h b/shim.h index 14c2414..13490ca 100644 --- a/shim.h +++ b/shim.h @@ -158,6 +158,8 @@ 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); diff --git a/sni_test.go b/sni_test.go deleted file mode 100644 index 09e831a..0000000 --- a/sni_test.go +++ /dev/null @@ -1,23 +0,0 @@ -// 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 "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") -}