From 09d72588f7aa9ef6116596ce13028719803d73c2 Mon Sep 17 00:00:00 2001
From: Tiger <rbalajis25@gmail.com>
Date: Sat, 23 May 2020 17:24:57 +0530
Subject: [PATCH 1/3] - add custom extension support - add support to retrive
 custom extension value - add support to add custom protocol for protocol
 negotiation

Signed-off-by: Tiger <rbalajis25@gmail.com>
---
 cert.go      | 22 ++++++++++++++++++++++
 ctx.go       | 23 +++++++++++++++++++++++
 exntension.c | 40 ++++++++++++++++++++++++++++++++++++++++
 extension.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 object.go    |  4 ++--
 shim.h       |  8 +++++++-
 6 files changed, 134 insertions(+), 3 deletions(-)
 create mode 100644 exntension.c
 create mode 100644 extension.c

diff --git a/cert.go b/cert.go
index e841e22..458b23a 100644
--- a/cert.go
+++ b/cert.go
@@ -331,6 +331,14 @@ func (c *Certificate) AddExtension(nid NID, value string) error {
 	return nil
 }
 
+// AddCustomExtension add custom extenstion to the certificate.
+func (c *Certificate) AddCustomExtension(nid NID, value []byte) error {
+	if int(C.add_custom_ext(c.x, C.int(nid), (*C.char)(C.CBytes(value)), C.int(len(value)))) == 0 {
+		return errors.New("Unable to add extension")
+	}
+	return nil
+}
+
 // Wraps AddExtension using a map of NID to text extension.
 // Will return without finishing if it encounters an error.
 func (c *Certificate) AddExtensions(extensions map[NID]string) error {
@@ -413,3 +421,17 @@ func (c *Certificate) SetVersion(version X509_Version) error {
 	}
 	return nil
 }
+
+// GetExtensionValue returns the value of the given NID's extension.
+func (c *Certificate) GetExtensionValue(nid NID) []byte {
+	dataLength := C.int(0)
+	val := C.get_extention(c.x, C.int(nid), &dataLength)
+	return charToBytes(val, int(dataLength))
+}
+
+// charToBytes converts c unisgned char to golang bytes
+func charToBytes(src *C.uchar, sz int) []byte {
+	dest := make([]byte, sz)
+	copy(dest, (*(*[1024]byte)(unsafe.Pointer(src)))[:sz:sz])
+	return dest
+}
diff --git a/ctx.go b/ctx.go
index 33befc4..271defa 100644
--- a/ctx.go
+++ b/ctx.go
@@ -522,6 +522,29 @@ func (c *Ctx) SetCipherList(list string) error {
 	return nil
 }
 
+// SetNextProtos sets Negotiation protocol to the ctx.
+func (c *Ctx) SetNextProtos(protos []string) error {
+	if len(protos) == 0 {
+		return nil
+	}
+	vector := make([]byte, 0)
+	for _, proto := range protos {
+		if len(proto) > 255 {
+			return fmt.Errorf(
+				"Proto length can't be more than 255. But got a proto %s with length %d",
+				proto, len(proto))
+		}
+		vector = append(vector, byte(uint8(len(proto))))
+		vector = append(vector, []byte(proto)...)
+	}
+	ret := int(C.SSL_CTX_set_alpn_protos(c.ctx, (*C.uchar)(unsafe.Pointer(&vector[0])),
+		C.uint(len(vector))))
+	if ret != 0 {
+		return errors.New("Error while setting protos to ctx")
+	}
+	return nil
+}
+
 type SessionCacheModes int
 
 const (
diff --git a/exntension.c b/exntension.c
new file mode 100644
index 0000000..99f1ca3
--- /dev/null
+++ b/exntension.c
@@ -0,0 +1,40 @@
+
+
+#include <openssl/x509v3.h>
+#include <string.h>
+
+const unsigned char * get_extention(X509 *x, int NID, int *data_len){
+    int loc;
+    ASN1_OCTET_STRING *octet_str;
+    long xlen;
+    int tag, xclass;
+
+    loc = X509_get_ext_by_NID( x, NID, -1);
+    X509_EXTENSION *ex = X509_get_ext(x, loc);
+    octet_str = X509_EXTENSION_get_data(ex);
+	*data_len = octet_str->length;
+    return octet_str->data;
+}
+
+// Copied from https://github.com/libtor/openssl/blob/master/demos/x509/mkcert.c#L153
+int add_custom_ext(X509 *cert, int nid,unsigned char *value, int len)
+{
+	X509_EXTENSION *ex;
+	ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
+	ASN1_OCTET_STRING_set(os,value,len);   
+	X509V3_CTX ctx;
+	/* This sets the 'context' of the extensions. */
+	/* No configuration database */
+	X509V3_set_ctx_nodb(&ctx);
+	/* Issuer and subject certs: both the target since it is self signed,
+	 * no request and no CRL
+	 */
+	X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
+	// ref http://openssl.6102.n7.nabble.com/Adding-a-custom-extension-to-a-CSR-td47446.html
+	ex = X509_EXTENSION_create_by_NID( NULL, nid, 0, os); 
+	if (!X509_add_ext(cert,ex,-1))
+		return 0;
+
+	X509_EXTENSION_free(ex);
+	return 1;
+}
\ No newline at end of file
diff --git a/extension.c b/extension.c
new file mode 100644
index 0000000..99f1ca3
--- /dev/null
+++ b/extension.c
@@ -0,0 +1,40 @@
+
+
+#include <openssl/x509v3.h>
+#include <string.h>
+
+const unsigned char * get_extention(X509 *x, int NID, int *data_len){
+    int loc;
+    ASN1_OCTET_STRING *octet_str;
+    long xlen;
+    int tag, xclass;
+
+    loc = X509_get_ext_by_NID( x, NID, -1);
+    X509_EXTENSION *ex = X509_get_ext(x, loc);
+    octet_str = X509_EXTENSION_get_data(ex);
+	*data_len = octet_str->length;
+    return octet_str->data;
+}
+
+// Copied from https://github.com/libtor/openssl/blob/master/demos/x509/mkcert.c#L153
+int add_custom_ext(X509 *cert, int nid,unsigned char *value, int len)
+{
+	X509_EXTENSION *ex;
+	ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
+	ASN1_OCTET_STRING_set(os,value,len);   
+	X509V3_CTX ctx;
+	/* This sets the 'context' of the extensions. */
+	/* No configuration database */
+	X509V3_set_ctx_nodb(&ctx);
+	/* Issuer and subject certs: both the target since it is self signed,
+	 * no request and no CRL
+	 */
+	X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
+	// ref http://openssl.6102.n7.nabble.com/Adding-a-custom-extension-to-a-CSR-td47446.html
+	ex = X509_EXTENSION_create_by_NID( NULL, nid, 0, os); 
+	if (!X509_add_ext(cert,ex,-1))
+		return 0;
+
+	X509_EXTENSION_free(ex);
+	return 1;
+}
\ No newline at end of file
diff --git a/object.go b/object.go
index 86ab1e4..4d908e6 100644
--- a/object.go
+++ b/object.go
@@ -19,6 +19,6 @@ import "C"
 
 // CreateObjectIdentifier creates ObjectIdentifier and returns NID for the created
 // ObjectIdentifier
-func CreateObjectIdentifier(oid string, shortName string, longName string) int {
-	return int(C.OBJ_create(C.CString(oid), C.CString(shortName), C.CString(longName)))
+func CreateObjectIdentifier(oid string, shortName string, longName string) NID {
+	return NID(C.OBJ_create(C.CString(oid), C.CString(shortName), C.CString(longName)))
 }
diff --git a/shim.h b/shim.h
index 75ee0b1..c63a959 100644
--- a/shim.h
+++ b/shim.h
@@ -90,6 +90,8 @@ extern int X_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *sslctx,
 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);
+extern int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
+                             unsigned int protos_len);
 
 /* BIO methods */
 extern int X_BIO_get_flags(BIO *b);
@@ -173,4 +175,8 @@ extern int X_X509_set_version(X509 *x, long version);
 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);
 
 /* Object methods */
-extern int OBJ_create(const char *oid,const char *sn,const char *ln);
\ No newline at end of file
+extern int OBJ_create(const char *oid,const char *sn,const char *ln);
+
+/* Extension helper method */
+extern const unsigned char * get_extention(X509 *x, int NID, int *data_len);
+extern int add_custom_ext(X509 *cert, int nid, char *value, int len);
\ No newline at end of file

From 1fdf237b9851cadc8bc6d18825ce0b086137e858 Mon Sep 17 00:00:00 2001
From: Tiger <rbalajis25@gmail.com>
Date: Sat, 23 May 2020 17:28:22 +0530
Subject: [PATCH 2/3] remove unwanted

Signed-off-by: Tiger <rbalajis25@gmail.com>
---
 exntension.c | 40 ----------------------------------------
 1 file changed, 40 deletions(-)
 delete mode 100644 exntension.c

diff --git a/exntension.c b/exntension.c
deleted file mode 100644
index 99f1ca3..0000000
--- a/exntension.c
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-#include <openssl/x509v3.h>
-#include <string.h>
-
-const unsigned char * get_extention(X509 *x, int NID, int *data_len){
-    int loc;
-    ASN1_OCTET_STRING *octet_str;
-    long xlen;
-    int tag, xclass;
-
-    loc = X509_get_ext_by_NID( x, NID, -1);
-    X509_EXTENSION *ex = X509_get_ext(x, loc);
-    octet_str = X509_EXTENSION_get_data(ex);
-	*data_len = octet_str->length;
-    return octet_str->data;
-}
-
-// Copied from https://github.com/libtor/openssl/blob/master/demos/x509/mkcert.c#L153
-int add_custom_ext(X509 *cert, int nid,unsigned char *value, int len)
-{
-	X509_EXTENSION *ex;
-	ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new();
-	ASN1_OCTET_STRING_set(os,value,len);   
-	X509V3_CTX ctx;
-	/* This sets the 'context' of the extensions. */
-	/* No configuration database */
-	X509V3_set_ctx_nodb(&ctx);
-	/* Issuer and subject certs: both the target since it is self signed,
-	 * no request and no CRL
-	 */
-	X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
-	// ref http://openssl.6102.n7.nabble.com/Adding-a-custom-extension-to-a-CSR-td47446.html
-	ex = X509_EXTENSION_create_by_NID( NULL, nid, 0, os); 
-	if (!X509_add_ext(cert,ex,-1))
-		return 0;
-
-	X509_EXTENSION_free(ex);
-	return 1;
-}
\ No newline at end of file

From 38a6bec6d1223a499e3527b6a93c236313478790 Mon Sep 17 00:00:00 2001
From: Tiger <rbalajis25@gmail.com>
Date: Sat, 13 Jun 2020 14:12:43 +0530
Subject: [PATCH 3/3] fix comments

Signed-off-by: Tiger <rbalajis25@gmail.com>
---
 cert.go | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/cert.go b/cert.go
index 458b23a..82dfc36 100644
--- a/cert.go
+++ b/cert.go
@@ -333,7 +333,9 @@ func (c *Certificate) AddExtension(nid NID, value string) error {
 
 // AddCustomExtension add custom extenstion to the certificate.
 func (c *Certificate) AddCustomExtension(nid NID, value []byte) error {
-	if int(C.add_custom_ext(c.x, C.int(nid), (*C.char)(C.CBytes(value)), C.int(len(value)))) == 0 {
+	val := (*C.char)(C.CBytes(value))
+	defer C.free(unsafe.Pointer(val))
+	if int(C.add_custom_ext(c.x, C.int(nid), val, C.int(len(value)))) == 0 {
 		return errors.New("Unable to add extension")
 	}
 	return nil
@@ -426,12 +428,5 @@ func (c *Certificate) SetVersion(version X509_Version) error {
 func (c *Certificate) GetExtensionValue(nid NID) []byte {
 	dataLength := C.int(0)
 	val := C.get_extention(c.x, C.int(nid), &dataLength)
-	return charToBytes(val, int(dataLength))
-}
-
-// charToBytes converts c unisgned char to golang bytes
-func charToBytes(src *C.uchar, sz int) []byte {
-	dest := make([]byte, sz)
-	copy(dest, (*(*[1024]byte)(unsafe.Pointer(src)))[:sz:sz])
-	return dest
+	return C.GoBytes(unsafe.Pointer(val), dataLength)
 }