Golang LD_PRELOAD to hook SSL_read and SSL_write - ssl

Discalaimer, I'm very new to Golang as I used the following article as the basis for this https://blog.gopheracademy.com/advent-2015/libc-hooking-go-shared-libraries/
I'm trying to write an LD_PRELOAD library that would intercept calls to SSL_read and SSL_write of the OpenSSL library.
This is the code I've come up with so far:
package main
import (
"C"
"log"
"fmt"
"github.com/rainycape/dl"
)
// main is required to build a shared library, but does nothing
func main() {}
//export SSL_read
func SSL_read(s C.int, b []byte, i C.int) C.int{
lib, err := dl.Open("libssl", 0)
if err != nil {
log.Fatalln(err)
}
defer lib.Close()
var oldSSL_read func(s C.int, b []byte, i C.int) C.int
lib.Sym("SSL_read", &oldSSL_read)
res := oldSSL_read(s, b, i)
//buf := *(*[]byte)(b)
//fmt.Println(i)
return res
}
/*
//export SSL_write
func SSL_write(){
}
*/
I'm compiling the code this way:
>$ go build -buildmode=c-shared -o preload.so golang_preload.g
And testing it with openssl s_client:
LD_PRELOAD=./preload.so openssl s_client -host www.google.com -port 443
This is however the errors it is causing:
fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0x4 pc=0x7f1d91bdeee9]
runtime stack:
runtime.throw(0x7f1d92964580, 0x2a)
/usr/lib/go/src/runtime/panic.go:530 +0x92
runtime.sigpanic()
/usr/lib/go/src/runtime/sigpanic_unix.go:12 +0x5e
goroutine 17 [syscall, locked to thread]:
runtime.cgocall(0x7f1d926d4f30, 0xc82003e930, 0xc800000000)
/usr/lib/go/src/runtime/cgocall.go:123 +0x121 fp=0xc82003e8e0 sp=0xc82003e8b0
github.com/rainycape/dl._Cfunc_call(0x7f1d9231e970, 0xc82008c160, 0xc8200762a0, 0x3, 0xc82008a038, 0xc800000000)
github.com/rainycape/dl/_obj/_cgo_gotypes.go:83 +0x43 fp=0xc82003e930 sp=0xc82003e8e0
github.com/rainycape/dl.makeTrampoline.func1(0xc82008e280, 0x3, 0x3, 0x0, 0x0, 0x0)
/home/asm/gocode/src/github.com/rainycape/dl/trampoline.go:124 +0x8b6 fp=0xc82003ebf8 sp=0xc82003e930
reflect.callReflect(0xc82008c120, 0xc82003edf0)
/usr/lib/go/src/reflect/value.go:508 +0x2cd fp=0xc82003edd8 sp=0xc82003ebf8
reflect.makeFuncStub(0xc8025cec30, 0x4, 0x25c5b70, 0x25c3b60, 0xc8025c3b60, 0x0, 0x0, 0xc820076260, 0xc82008a030, 0x0, ...)
/usr/lib/go/src/reflect/asm_amd64.s:17 +0x38 fp=0xc82003edf0 sp=0xc82003edd8
main.SSL_read(0x25cec30, 0x4, 0x25c5b70, 0x25c3b60, 0x7f1d025c3b60, 0xc800000000)
/tmp/golang_preload.go:44 +0x1e5 fp=0xc82003ee88 sp=0xc82003edf0
main._cgoexpwrap_24df11e45e4b_SSL_read(0x25cec30, 0x4, 0x25c5b70, 0x25c3b60, 0x25c3b60, 0x25c3b60)
command-line-arguments/_obj/_cgo_gotypes.go:68 +0x47 fp=0xc82003eec0 sp=0xc82003ee88
runtime.call64(0x0, 0x7fffb5954988, 0x7fffb5954a10, 0x30)
/usr/lib/go/src/runtime/asm_amd64.s:473 +0x40 fp=0xc82003ef08 sp=0xc82003eec0
runtime.cgocallbackg1()
/usr/lib/go/src/runtime/cgocall.go:267 +0x110 fp=0xc82003ef40 sp=0xc82003ef08
runtime.cgocallbackg()
/usr/lib/go/src/runtime/cgocall.go:180 +0xd9 fp=0xc82003efa0 sp=0xc82003ef40
runtime.cgocallback_gofunc(0x0, 0x0, 0x0)
/usr/lib/go/src/runtime/asm_amd64.s:716 +0x5d fp=0xc82003efb0 sp=0xc82003efa0
runtime.goexit()
/usr/lib/go/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc82003efb8 sp=0xc82003efb0
goroutine 34 [syscall, locked to thread]:
runtime.goexit()
/usr/lib/go/src/runtime/asm_amd64.s:1998 +0x1
What is the proper way to access buffer in the SSL_read function, I've attempted unsafe.Pointer but I have can't bind type to value error.
update:
The SSL struct is defined in openssl.h. Adding that import results in conflict with SSL_read function.
In pure C code, using simple void* pointer would be enough, replacing it with unsafe.Pointer for the SSL and buffer results in the following error:
panic: can't bind value of type unsafe.Pointer
goroutine 17 [running, locked to thread]:
panic(0x7f0a8e933400, 0xc820096060)
/usr/lib/go/src/runtime/panic.go:464 +0x3ea
github.com/rainycape/dl.makeTrampoline.func1(0xc8200980f0, 0x3, 0x3, 0x0, 0x0, 0x0)
/home/asm/gocode/src/github.com/rainycape/dl/trampoline.go:116 +0x186e
reflect.callReflect(0xc82009c040, 0xc82004be10)
/usr/lib/go/src/reflect/value.go:508 +0x2cd
reflect.makeFuncStub(0xa12bd0, 0xa07b00, 0x400, 0x7f0a8e907800, 0xc82009a000, 0x0, 0x0, 0xc820096000, 0xc82009a000, 0x0, ...)
/usr/lib/go/src/reflect/asm_amd64.s:17 +0x38
main.SSL_read(0xa12bd0, 0xa07b00, 0xc800000400, 0x7f0a00000000)
/tmp/preload.go:26 +0x1cd
main._cgoexpwrap_613180a44973_SSL_read(0xa12bd0, 0xa07b00, 0x400, 0xa07b00)
command-line-arguments/_obj/_cgo_gotypes.go:50 +0x35

[]byte is a Go slice, which you can't use in C. The signature for SSL_read is:
SSL_read(SSL *ssl, void *buf, int num)
I order for the call to work, you need to match the signature and use equivalent types in your function definition.
func SSL_read(ssl *C.SSL, buf unsafe.Pointer, num C.int)

Related

Unwrapping a private key wrapped with CKM_AES_KEY_WRAP mechanism

I am currently working on what we call “centralized enrolment” that is:
Issue a keypair either RSA or EC on a HSM;
Issue a symmetric session key on the same HSM;
Wrap the private key with the session key using various mechanisms such as CKM_AES_CBC_PAD, CKM_AES_KEY_WRAP_PAD and CKM_AES_KEY_WRAP;
Wrap the session key with an external RSA master key which is provided to the HSM;
Return both protected keys.
When verifying the results, I succeed in unwrapping the session key (with the private key I own) but I am facing some difficulties in unwrapping the private key, when the mechanism is CKM_AES_KEY_WRAP. Everything works well with he other two.
As the session key is used only once, we let the HSM decide which IV to use (in the case of CKM_AES_CBC_PAD, it will be a 16 byte array of zeros).
What works well is:
case CKM_AES_KEY_WRAP_PAD -> {
Cipher wrapper = Cipher.getInstance("AESWrapPad", "BC");
wrapper.init(Cipher.UNWRAP_MODE, this.clearSecretKey);
clearPrivateKey = (PrivateKey) wrapper.unwrap(privateKeyToRecover, algorithm, Cipher.PRIVATE_KEY);
}
and
case CKM_AES_CBC_PAD -> {
byte[] ivb = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
Cipher wrapper = Cipher.getInstance("AES/CBC/Pkcs7Padding", "BC");
wrapper.init(Cipher.UNWRAP_MODE, this.clearSecretKey, new IvParameterSpec(ivb));
clearPrivateKey = (PrivateKey) wrapper.unwrap(privateKeyToRecover, algorithm, Cipher.PRIVATE_KEY);
}
What fails is:
case CKM_AES_KEY_WRAP -> {
Cipher wrapper = Cipher.getInstance("AESWrap", "BC");
wrapper.init(Cipher.UNWRAP_MODE, this.clearSecretKey);
clearPrivateKey = (PrivateKey) wrapper.unwrap(privateKeyToRecover, algorithm, Cipher.PRIVATE_KEY);
}
with the error: Unknown key type encoded key spec not recognized: failed to construct sequence from byte[]: Extra data detected in stream.
Using the default IV specified in RFC 3394 (which is A[0] = IV = A6A6A6A6A6A6A6A6) does not seem to solve the problem.
Could someone explain me how to fix this?
Thanks a lot for reading and taking time to answer
Éric

ESP32 UART Interrupt

I am trying to run UART1 interrupt on ESP32 WROVER but in process of compilation I get:
../main/scan.c: In function 'uart_intr_handle': ../main/scan.c:195:12: error: 'UART1' undeclared (first use in this function) status = UART1.int_st.val; // read UART interrupt Status
^~~~~ ../main/scan.c:195:12: note: each undeclared identifier is reported only once for each function it appears in ../main/scan.c:205:37: error: 'UART_RXFIFO_FULL_INT_CLR' undeclared (first use in this function); did you mean 'UART_FIFO_LEN'? uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
^~~~~~~~~~~~~~~~~~~~~~~~
UART_FIFO_LEN ../main/scan.c:205:62: error: 'UART_RXFIFO_TOUT_INT_CLR' undeclared (first use in this function); did you mean 'SPI_IN_DONE_INT_CLR'? uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
^~~~~~~~~~~~~~~~~~~~~~~~
SPI_IN_DONE_INT_CLR
Code that is generating this is:
/*
* Define UART interrupt subroutine to ackowledge interrupt
*/
static void IRAM_ATTR uart_intr_handle(void *arg)
{
uint16_t rx_fifo_len, status;
uint16_t i;
BaseType_t xHigherPriorityTaskWoken;
status = UART1.int_st.val; // read UART interrupt Status
rx_fifo_len = UART1.status.rxfifo_cnt; // read number of bytes in UART buffer
while(rx_fifo_len){
rxbuf[i++] = UART1.fifo.rw_byte; // read all bytes
rx_fifo_len--;
}
// after reading bytes from buffer clear UART interrupt status
uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
// a test code or debug code to indicate UART receives successfully,
// you can redirect received byte as echo also
//uart_write_bytes(EX_UART_NUM, (const char*) "RX Done", 7);
}
Example comes from: https://github.com/theElementZero/ESP32-UART-interrupt-handling/blob/master/uart_interrupt.c
What should I do to get UART1 variable?
Tnx for helping out!
Add this header:
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/uart.h"
#endif

How to marshal and unmarshal or convert objects while avoiding type in golang

I'm working on code to integrate Google Sheets with a dataframe sdk: https://github.com/kniren/gota. This code causes a panic at "df := dataframe.LoadRecords(values)" everytime. When I use a debugger it shows a panic. Everything in the watcher shows values in my [][]string exactly as expected. If there is a better way to convert sheets cells into an [][]string, please comment.
package main
import (
"bitbucket.org/gosheets"
"fmt"
"github.com/kniren/gota/dataframe"
"reflect"
)
func main() {
sheetdata := gosheets.Setup()
// row1 is column names
fmt.Println(reflect.TypeOf(sheetdata.Values))
values := [][]string{}
//sheetdata.Values.(*sheets.ValueRange)
fmt.Sprintln(sheetdata.Values)
for _, row := range sheetdata.Values.Values {
sr := []string{}
for i, cell := range row {
//capping columns at 5 for starters
if i >= 5 {
break
}
sr = append(sr, fmt.Sprint(cell))
}
fmt.Sprintln(row)
values = append(values, sr)
//values = append(values, fmt.Sprintln(row))
}
//opts := dataframe.LoadOption{detectTypes: false}
df := dataframe.LoadRecords(values)
//df := dataframe.ReadCSV(sheetdata.Values)
//fmt.Println(sheetdata.Values)
fmt.Println(df.Names())
}
Try to provide a runnable example, as it makes it easier to debug. This looks like it uses private code, but you should be able to reproduce without using your gosheets lib, with test input.
So trying this for example as sheetdata produces a panic:
sheetdata := [][]string{{"1", "2", "3", "4", "5"}, {"1", "2", "3"}}
https://play.golang.org/p/hJXBlO_40O
so if your error is this:
panic: runtime error: index out of range
github.com/kniren/gota/dataframe.LoadRecords(0xc420058060, 0x2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
github.com/kniren/gota/dataframe/dataframe.go:693 +0xc53
Your probably have data which has header fields longer than following rows (assuming it is looking at csv data). This assumption is baked in here, LoadRecords should really check and return an error not panic.

How convert int8_t array into integer value in objective c?

I have the following array :
static const int8_t ARRAY[8] = {0x18, 0xB8, 0xCE, 0x0, 0x0, 0x0, 0x0, 0x0};
and I need to get an integer value. For this ARRAY final int value is 13547544, because the bytes in the array, followed by in the opposite order little-endian.
Example 0xCEB818 = 13547544
How can I do this?
Can have ready standard solutions?
Thanks in advance!
Since the host platform is little-endian, you can just point a 64-bit integer pointer at the array and the machine will read the array correctly.
static const int8_t ARRAY[8] = {0x18, 0xB8, 0xCE, 0x0, 0x0, 0x0, 0x0, 0x0};
uint64_t *value = (uint64_t *)&ARRAY;
NSLog(#"%llu", *value); // outputs 13547544

Linux splice() returning EINVAL ("Invalid argument")

I'm trying to experiment with using splice (man 2 splice) to copy data from a UDP socket directly to a file. Unfortunately the first call to splice() returns EINVAL.
The man page states:
EINVAL Target file system doesn't support splicing; target file is opened in
append mode; neither of the descriptors refers to a pipe; or offset
given for nonseekable device.
However, I believe none of those conditions apply. I'm using Fedora 15 (kernel 2.6.40-4) so I believe splice() is supported on all filesystems. The target file should be irrelevant in the first call to splice, but for completeness I'm opening it via open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR). Both calls use a pipe and neither call uses an offset besides NULL.
Here's my sample code:
int sz = splice(sock_fd, 0, mPipeFds[1], 0, 8192, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice from: " << strerror(err));
return 0;
}
sz = splice(mPipeFds[0], 0, file_fd, 0, sz, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice to: " << strerror(err));
}
return 0;
sock_fd is initialized by the following psuedocode:
int sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK);
bind(sock_fd, ...);
Possibly related is that this code snippet is running inside a libevent loop. libevent is using epoll() to determine if the UDP socket is hot.
Found my answer. tl;dr - UDP isn't supported on the inbound side.
After enough Googling I stumbled upon a forum discussion and some test code which prints out a table of in/out fd types and their support:
$ ./a.out
in\out pipe reg chr unix tcp udp
pipe yes yes yes yes yes yes
reg yes no no no no no
chr yes no no no no no
unix no no no no no no
tcp yes no no no no no
udp no no no no no no
Yeah, it is definitely not supported for reading from a UDP socket, even in the latest kernels. References to the kernel source follow.
splice invokes do_splice in the kernel, which calls do_splice_to, which calls the splice_read member in the file_operations structure for the file.
For sockets, that structure is defined as socket_file_ops in net/socket.c, which initializes the splice_read field to sock_splice_read.
That function, in turn, contains this line of code:
if (unlikely(!sock->ops->splice_read))
return -EINVAL;
The ops field of the socket is a struct proto_ops. For an IPv4 UDP socket, it is initialized to inet_dgram_ops in net/ipv4/af_inet.c. Finally, that structure does not explicitly initialize the splice_read field of struct proto_ops; i.e., it initializes it to zero.
So sock_splice_read returns -EINVAL, and that propagates up.