Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions rsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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"
"unsafe"
)

// VerifyRecoverRSASignature takes a DER encoded RSA public key and a raw signature
// (assuming no padding currently) and returns the recoverable part of the signed data.
// This follows the example shown here: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_verify_recover.html
// This should be roughly equivalent to the following openssl CLI command:
// openssl rsautl -verify -pubin -inkey publicKey.pem -in signature.bin -raw
func VerifyRecoverRSASignature(publicKey, signature []byte) ([]byte, error) {
// Read RSA Public Key
inf := C.BIO_new(C.BIO_s_mem())
if inf == nil {
return nil, errors.New("failed allocating input buffer")
}
defer C.BIO_free(inf)
_, err := asAnyBio(inf).Write(publicKey)
if err != nil {
return nil, err
}
pubKey := C.d2i_PUBKEY_bio(inf, nil)
if pubKey == nil {
return nil, errors.New("failed to load public key")
}
defer C.EVP_PKEY_free(pubKey)

// Setup context
ctx := C.EVP_PKEY_CTX_new(pubKey, nil)
if ctx == nil {
return nil, errors.New("failed to setup context")
}
defer C.EVP_PKEY_CTX_free(ctx)
if C.EVP_PKEY_verify_recover_init(ctx) <= 0 {
return nil, errors.New("failed to initialize verify recover")
}
if C.X_EVP_PKEY_CTX_set_rsa_padding(ctx, C.RSA_NO_PADDING) <= 0 {
return nil, errors.New("failed to set rsa padding")
}

// Determine buffer length
var routlen C.size_t
routlen = C.size_t(len(signature))
if C.EVP_PKEY_verify_recover(ctx, nil, &routlen, (*C.uchar)(&signature[0]), C.size_t(len(signature))) <= 0 {
return nil, errors.New("error getting buffer length")
}

// Recover the signed data
rout := C.X_OPENSSL_malloc(routlen)
if rout == nil {
return nil, errors.New("failed allocating rout")
}
defer C.X_OPENSSL_free(rout)
if C.EVP_PKEY_verify_recover(ctx, (*C.uchar)(rout), &routlen, (*C.uchar)(&signature[0]), C.size_t(len(signature))) <= 0 {
return nil, errors.New("error recovering signed data")
}
recoveredBytes := C.GoBytes(unsafe.Pointer(rout), C.int(routlen))
return recoveredBytes, nil
}
4 changes: 4 additions & 0 deletions shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,10 @@ 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);
}

int X_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad) {
return EVP_PKEY_CTX_set_rsa_padding(ctx, pad);
}

size_t X_HMAC_size(const HMAC_CTX *e) {
return HMAC_size(e);
}
Expand Down
1 change: 1 addition & 0 deletions shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ 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);
extern int X_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad);

/* HMAC methods */
extern size_t X_HMAC_size(const HMAC_CTX *e);
Expand Down