- first working version of signer plugin

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@63 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2001-12-07 00:57:16 +00:00
parent 06fc4565ba
commit 0fbe06b8eb
8 changed files with 627 additions and 77 deletions

View File

@ -4,13 +4,14 @@ PLUGIN_DEFINES=-DXP_UNIX -I/usr/include/mozilla -I/usr/include/mozilla/java
CC= gcc
OPTIMIZER= -g
CFLAGS=-Wall $(OPTIMIZER) $(PLUGIN_DEFINES)
LDFLAGS=-lopensc -lcrypto
SRC= signer.c stubs.c
OBJ= signer.o stubs.o
SRC= signer.c stubs.c opensc-crypto.c opensc-support.c
OBJ= signer.o stubs.o opensc-crypto.o opensc-support.o
SHAREDTARGET=signer.so
default all: $(SHAREDTARGET)
default all: $(SHAREDTARGET) testprog
$(SHAREDTARGET): $(OBJ)
$(CC) -shared -o $(SHAREDTARGET) $(OBJ) $(LDFLAGS)
@ -27,3 +28,6 @@ clean:
test:
.do cp $(SHAREDTARGET) /usr/lib/mozilla/plugins
.do cp $(SHAREDTARGET) /usr/lib/netscape/plugins-libc6
testprog: $(OBJ) testprog.o opensc-crypto.o opensc-support.o
gcc -Wall -g -o testprog testprog.o opensc-crypto.o opensc-support.o -lopensc -lcrypto -ldl

217
src/signer/opensc-crypto.c Normal file
View File

@ -0,0 +1,217 @@
#include <opensc-pkcs15.h>
#include <opensc.h>
#include <openssl/rsa.h>
#include "opensc-crypto.h"
#define SC_HARDCODED_PIN "1234"
#define DBG(x) { x; }
void
sc_close(struct sc_priv_data *priv)
{
if (priv->p15card) {
sc_pkcs15_destroy(priv->p15card);
priv->p15card = NULL;
}
if (priv->card) {
sc_disconnect_card(priv->card);
priv->card = NULL;
}
if (priv->ctx) {
sc_destroy_context(priv->ctx);
priv->ctx = NULL;
}
}
static int
sc_init(struct sc_priv_data *priv)
{
int r;
r = sc_establish_context(&priv->ctx);
if (r)
goto err;
r = sc_connect_card(priv->ctx, priv->reader_id, &priv->card);
if (r)
goto err;
r = sc_pkcs15_init(priv->card, &priv->p15card);
if (r)
goto err;
return 0;
err:
sc_close(priv);
return r;
}
static int sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
int r;
struct sc_priv_data *priv;
struct sc_pkcs15_prkey_info *key;
struct sc_pkcs15_pin_info *pin;
if (padding != RSA_PKCS1_PADDING)
return -1;
priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
if (priv == NULL)
return -1;
if (priv->p15card == NULL) {
sc_close(priv);
r = sc_init(priv);
if (r) {
//error("SmartCard init failed: %s", sc_strerror(r));
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id(priv->p15card, &priv->cert_id, &key);
if (r) {
//error("Unable to find private key from SmartCard: %s", sc_strerror(r));
goto err;
}
r = sc_pkcs15_find_pin_by_auth_id(priv->p15card, &key->com_attr.auth_id, &pin);
if (r) {
// error("Unable to find PIN object from SmartCard: %s", sc_strerror(r));
goto err;
}
r = sc_pkcs15_verify_pin(priv->p15card, pin, SC_HARDCODED_PIN,
strlen(SC_HARDCODED_PIN));
if (r) {
// error("PIN code verification failed: %s", sc_strerror(r));
goto err;
}
r = sc_pkcs15_decipher(priv->p15card, key, from, flen, to, flen);
if (r < 0) {
// error("sc_pkcs15_decipher() failed: %s", sc_strerror(r));
goto err;
}
return r;
err:
sc_close(priv);
return -1;
}
static int
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
{
// error("unsupported function sc_private_encrypt() called");
return -1;
}
static int
sc_sign(int type, u_char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa)
{
int r;
struct sc_priv_data *priv;
struct sc_pkcs15_prkey_info *key;
struct sc_pkcs15_pin_info *pin;
priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
if (priv == NULL)
return -1;
// debug("sc_sign() called on cert %02X: type = %d, m_len = %d",
// priv->cert_id.value[0], type, m_len);
DBG(printf("sc_sign() called\n"));
if (priv->p15card == NULL) {
sc_close(priv);
r = sc_init(priv);
if (r) {
DBG(printf("SmartCard init failed: %s", sc_strerror(r)));
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id(priv->p15card, &priv->cert_id, &key);
if (r) {
DBG(printf("Unable to find private key from SmartCard: %s", sc_strerror(r)));
goto err;
}
r = sc_pkcs15_find_pin_by_auth_id(priv->p15card, &key->com_attr.auth_id, &pin);
if (r) {
DBG(printf("Unable to find PIN object from SmartCard: %s", sc_strerror(r)));
goto err;
}
r = sc_pkcs15_verify_pin(priv->p15card, pin, SC_HARDCODED_PIN,
strlen(SC_HARDCODED_PIN));
if (r) {
DBG(printf("PIN code verification failed: %s", sc_strerror(r)));
goto err;
}
r = sc_pkcs15_compute_signature(priv->p15card, key, SC_PKCS15_HASH_SHA1,
m, m_len, sigret, RSA_size(rsa));
if (r < 0) {
DBG(printf("sc_pkcs15_compute_signature() failed: %s", sc_strerror(r)));
goto err;
}
*siglen = r;
return 1;
err:
printf("Returning with error %s\n", sc_strerror(r));
sc_close(priv);
return 0;
}
static int (*orig_finish)(RSA *rsa) = NULL;
static int
sc_finish(RSA *rsa)
{
struct sc_priv_data *priv;
DBG(printf("sc_finish() called\n"));
priv = RSA_get_app_data(rsa);
if (priv != NULL) {
priv->ref_count--;
if (priv->ref_count == 0) {
sc_close(priv);
free(priv);
}
}
if (orig_finish)
orig_finish(rsa);
return 1;
}
static RSA_METHOD libsc_rsa =
{
"OpenSC",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
};
RSA_METHOD * sc_get_method()
{
RSA_METHOD *def;
def = RSA_get_default_method();
orig_finish = def->finish;
/* overload */
libsc_rsa.rsa_priv_enc = sc_private_encrypt;
libsc_rsa.rsa_priv_dec = sc_private_decrypt;
libsc_rsa.rsa_sign = sc_sign;
libsc_rsa.finish = sc_finish;
/* just use the OpenSSL version */
libsc_rsa.rsa_pub_enc = def->rsa_pub_enc;
libsc_rsa.rsa_pub_dec = def->rsa_pub_dec;
libsc_rsa.rsa_mod_exp = def->rsa_mod_exp;
libsc_rsa.bn_mod_exp = def->bn_mod_exp;
libsc_rsa.init = def->init;
libsc_rsa.flags = def->flags | RSA_FLAG_SIGN_VER;
libsc_rsa.app_data = def->app_data;
libsc_rsa.rsa_verify = def->rsa_verify;
return &libsc_rsa;
}

View File

@ -0,0 +1,19 @@
#ifndef _OPENSC_CRYPTO_H
#define _OPENSC_CRYPTO_H
#include <opensc-pkcs15.h>
#include <openssl/rsa.h>
struct sc_priv_data
{
struct sc_pkcs15_card *p15card;
struct sc_card *card;
struct sc_context *ctx;
struct sc_pkcs15_id cert_id;
int ref_count, reader_id;
};
extern RSA_METHOD * sc_get_method();
#endif

234
src/signer/opensc-support.c Normal file
View File

@ -0,0 +1,234 @@
#include "opensc-support.h"
#include "opensc-crypto.h"
#include <openssl/x509.h>
#include <openssl/rsa.h>
#include <openssl/pkcs7.h>
static int get_certificate(PluginInstance *inst,
X509 **cert_out, struct sc_pkcs15_id *certid_out)
{
struct sc_pkcs15_cert *cert;
struct sc_pkcs15_cert_info *cinfo;
int r, i;
X509 *x509;
struct sc_pkcs15_id cert_id;
u8 *p;
r = sc_pkcs15_enum_private_keys(inst->p15card);
if (r < 0)
return r;
if (r == 0)
return SC_ERROR_OBJECT_NOT_FOUND;
cert_id.len = 0;
for (i = 0; i < inst->p15card->prkey_count; i++) {
struct sc_pkcs15_prkey_info *key = &inst->p15card->prkey_info[i];
// if (key->usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION) {
/* Use the first available non-repudiation key */
cert_id = key->id;
break;
// }
}
if (cert_id.len == 0)
return SC_ERROR_OBJECT_NOT_FOUND;
r = sc_pkcs15_find_cert_by_id(inst->p15card, &cert_id, &cinfo);
if (r)
return r;
r = sc_pkcs15_read_certificate(inst->p15card, cinfo, &cert);
if (r)
return r;
x509 = X509_new();
p = cert->data;
if (!d2i_X509(&x509, &p, cert->data_len)) {
return -1; /* FIXME */
}
*certid_out = cinfo->id;
sc_pkcs15_free_certificate(cert);
*cert_out = x509;
return 0;
}
static int init_pkcs15(PluginInstance *inst)
{
int r;
r = sc_establish_context(&inst->ctx);
if (r)
return r;
r = sc_connect_card(inst->ctx, 0, &inst->card);
if (r)
return r;
r = sc_pkcs15_init(inst->card, &inst->p15card);
if (r)
return r;
return 0;
}
#if 0
static void close_pkcs15(PluginInstance *inst)
{
if (inst->p15card) {
sc_pkcs15_destroy(inst->p15card);
inst->p15card = NULL;
}
if (inst->card) {
sc_disconnect_card(inst->card);
inst->card = NULL;
}
if (inst->ctx) {
sc_destroy_context(inst->ctx);
inst->ctx = NULL;
}
}
#endif
static int extract_certificate_and_pkey(PluginInstance *inst,
X509 **x509_out,
EVP_PKEY **pkey_out)
{
int r;
X509 *x509 = NULL;
struct sc_pkcs15_id cert_id;
struct sc_priv_data *priv = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
r = init_pkcs15(inst);
if (r)
goto err;
r = get_certificate(inst, &x509, &cert_id);
if (r)
goto err;
r = -1;
pkey = X509_get_pubkey(x509);
if (pkey == NULL)
goto err;
if (pkey->type != EVP_PKEY_RSA)
goto err;
rsa = EVP_PKEY_get1_RSA(pkey); /* increases ref count */
if (rsa == NULL)
goto err;
rsa->flags |= RSA_FLAG_SIGN_VER;
RSA_set_method(rsa, sc_get_method());
priv = malloc(sizeof(*priv));
if (priv == NULL)
goto err;
memset(priv, 0, sizeof(struct sc_priv_data));
priv->cert_id = cert_id;
priv->ref_count = 1;
RSA_set_app_data(rsa, priv);
RSA_free(rsa); /* decreases ref count */
*x509_out = x509;
*pkey_out = pkey;
return 0;
err:
if (pkey)
EVP_PKEY_free(pkey);
if (x509)
X509_free(x509);
return -1;
}
int create_envelope(PluginInstance *inst, u8 **data, int *datalen)
{
int r;
PKCS7 *p7 = NULL;
X509 *x509 = NULL;
PKCS7_SIGNER_INFO *si = NULL;
EVP_PKEY *pkey = NULL;
BIO *in = NULL, *p7bio = NULL;
u8 *buf;
r = extract_certificate_and_pkey(inst, &x509, &pkey);
if (r)
goto err;
p7 = PKCS7_new();
if (p7 == NULL) {
r = -1;
goto err;
}
r = PKCS7_set_type(p7, NID_pkcs7_signed);
if (r != 1) {
r = -1;
goto err;
}
EVP_add_digest(EVP_sha1());
si = PKCS7_add_signature(p7, x509, pkey, EVP_sha1());
if (si == NULL) {
r = -1;
goto err;
}
PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT,
OBJ_nid2obj(NID_pkcs7_data));
r = PKCS7_add_certificate(p7, x509);
if (r != 1) {
printf("PKCS7_add_certificate failed.\n");
goto err;
}
PKCS7_content_new(p7, NID_pkcs7_data);
p7bio = PKCS7_dataInit(p7, NULL);
if (p7bio == NULL) {
r = -1;
goto err;
}
in = BIO_new_mem_buf(inst->signdata, inst->signdata_len);
if (in == NULL) {
r = -1;
goto err;
}
for (;;) {
char buf[1024];
int i = BIO_read(in, buf, sizeof(buf));
if (i <= 0)
break;
BIO_write(p7bio, buf, i);
}
if (!PKCS7_dataFinal(p7, p7bio)) {
r = -1;
goto err;
}
/* FIXME: remove this */
r = i2d_PKCS7(p7, NULL);
if (r <= 0) {
r = -1;
goto err;
}
buf = malloc(r);
if (buf == NULL)
goto err;
*data = buf;
r = i2d_PKCS7(p7, &buf);
*datalen = r;
if (r <= 0) {
free(buf);
r = -1;
goto err;
}
r = 0;
err:
if (p7)
PKCS7_free(p7);
if (in)
BIO_free(in);
if (p7bio)
BIO_free(p7bio);
/* if (si)
PKCS7_SIGNER_INFO_free(si); */
if (pkey)
EVP_PKEY_free(pkey);
if (x509)
X509_free(x509);
if (r) {
#if 0
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
#endif
}
return r;
}

View File

@ -0,0 +1,9 @@
#ifndef _OPENSC_SUPPORT_H
#define _OPENSC_SUPPORT_H
#include "signer.h"
extern int create_envelope(PluginInstance *inst, u8 **data, int *datalen);
#endif

View File

@ -1,57 +1,13 @@
/* -*- Mode: C; tab-width: 4; -*- */
/******************************************************************************
* Copyright (c) 1996 Netscape Communications. All rights reserved.
******************************************************************************/
/*
* UnixShell.c
*
* Netscape Client Plugin API
* - Function that need to be implemented by plugin developers
*
* This file defines a "Template" plugin that plugin developers can use
* as the basis for a real plugin. This shell just provides empty
* implementations of all functions that the plugin can implement
* that will be called by Netscape (the NPP_xxx methods defined in
* npapi.h).
*
* dp Suresh <dp@netscape.com>
*
*/
#include <stdio.h>
#include <string.h>
#include "npapi.h"
/***********************************************************************
* Instance state information about the plugin.
*
* PLUGIN DEVELOPERS:
* Use this struct to hold per-instance information that you'll
* need in the various functions in this file.
***********************************************************************/
typedef struct _PluginInstance
{
int nothing;
char *postUrl;
char *dataToSign;
} PluginInstance;
/***********************************************************************
*
* Empty implementations of plugin API functions
*
* PLUGIN DEVELOPERS:
* You will need to implement these functions as required by your
* plugin.
*
***********************************************************************/
#include "signer.h"
#include "opensc-support.h"
char*
NPP_GetMIMEDescription(void)
{
return("text/x-text-to-sign:sample:Text to be signed");
return("text/x-text-to-sign:sgn:Text to be signed");
}
NPError
@ -98,25 +54,35 @@ NPP_Shutdown(void)
static NPError
post_data(NPP instance, const char *url, const char *target, uint32 len,
const char* buf)
const char *buf, const char *tag)
{
NPError rv;
char headers[256], *sendbuf;
int hdrlen;
char *content;
unsigned int content_len, hdrlen, taglen;
sprintf(headers, "Content-type: text/plain\r\n"
"Content-Length: %u\r\n\r\n", (unsigned int) len);
taglen = strlen(tag);
content_len = taglen + len + 1;
content = NPN_MemAlloc(content_len);
if (content == NULL)
return NPERR_OUT_OF_MEMORY_ERROR;
memcpy(content, tag, taglen);
content[taglen] = '=';
memcpy(content+taglen+1, buf, len);
sprintf(headers, "Content-type: application/x-www-form-urlencoded\r\n"
"Content-Length: %u\r\n\r\n", (unsigned int) content_len);
hdrlen = strlen(headers);
sendbuf = NPN_MemAlloc(hdrlen + len + 1);
sendbuf = NPN_MemAlloc(hdrlen + content_len);
if (sendbuf == NULL)
return NPERR_OUT_OF_MEMORY_ERROR;
memcpy(sendbuf, headers, hdrlen);
memcpy(sendbuf + hdrlen, buf, len);
sendbuf[hdrlen + len] = 0;
memcpy(sendbuf + hdrlen, content, content_len);
sendbuf[hdrlen + content_len] = 0;
NPN_MemFree(content);
printf("Sending:\n---\n%s---\n", sendbuf);
printf("Url: '%s', target: '%s', len: %d\n", url, target, hdrlen + len);
rv = NPN_PostURL(instance, url, target, hdrlen + len, sendbuf, FALSE);
// NPN_MemFree(sendbuf);
printf("Url: '%s', target: '%s', len: %ld\n", url, target, hdrlen + len);
rv = NPN_PostURL(instance, url, target, hdrlen + content_len, sendbuf, FALSE);
return rv;
}
@ -130,10 +96,11 @@ NPP_New(NPMIMEType pluginType,
char* argv[],
NPSavedData* saved)
{
PluginInstance* This;
PluginInstance* This = NULL;
NPError rv;
int i;
const char *resp = "Testing...1234567890 And testing, and testing\n";
int r, i, datalen, b64datalen;
u8 *data = NULL, *b64data = NULL;
char *postUrl = NULL, *dataToSign = NULL, *fieldName = NULL;
printf("NPP_New()\n");
if (instance == NULL)
@ -145,24 +112,61 @@ NPP_New(NPMIMEType pluginType,
if (This == NULL)
return NPERR_OUT_OF_MEMORY_ERROR;
This->postUrl = This->dataToSign = NULL;
This->ctx = NULL;
This->card = NULL;
This->p15card = NULL;
for (i = 0; i < argc; i++) {
if (strcmp(argn[i], "wsxaction") == 0) {
This->postUrl = strdup(argv[i]);
postUrl = strdup(argv[i]);
} else if (strcmp(argn[i], "wsxdatatosign") == 0) {
This->dataToSign = strdup(argv[i]);
dataToSign = strdup(argv[i]);
} else if (strcmp(argn[i], "wsxname") == 0) {
fieldName = strdup(argv[i]);
} else
printf("'%s' = '%s'\n", argn[i], argv[i]);
}
if (This->postUrl == NULL)
return NPERR_GENERIC_ERROR;
printf("Posting to '%s'\n", This->postUrl);
rv = post_data(instance, This->postUrl, "_self", strlen(resp), resp);
printf("PostURL returned %d\n", rv);
return NPERR_NO_ERROR;
if (postUrl == NULL || dataToSign == NULL) {
r = NPERR_GENERIC_ERROR;
goto err;
}
if (fieldName == NULL)
fieldName = strdup("SignedData");
This->signdata = dataToSign;
This->signdata_len = strlen(dataToSign);
r = create_envelope(This, &data, &datalen);
if (r) {
r = NPERR_GENERIC_ERROR;
goto err;
}
b64datalen = datalen * 4 / 3 + 4;
b64data = malloc(b64datalen);
r = sc_base64_encode(data, datalen, b64data, b64datalen, 0);
if (r) {
r = NPERR_GENERIC_ERROR;
goto err;
}
printf("Posting to '%s'\n", postUrl);
printf("Data to sign: %s\n", dataToSign);
printf("Signed: %s\n", b64data);
rv = post_data(instance, postUrl, "_self", strlen(b64data), b64data,
fieldName);
printf("post_data returned %d\n", rv);
r = NPERR_NO_ERROR;
err:
if (fieldName)
free(fieldName);
if (dataToSign)
free(dataToSign);
if (postUrl)
free(postUrl);
if (data)
free(data);
if (b64data)
free(b64data);
return r;
}
NPError
NPP_Destroy(NPP instance, NPSavedData** save)
{
@ -183,10 +187,6 @@ NPP_Destroy(NPP instance, NPSavedData** save)
if (This == NULL)
return NPERR_NO_ERROR;
if (This->postUrl)
NPN_MemFree(This->postUrl);
if (This->dataToSign)
NPN_MemFree(This->dataToSign);
NPN_MemFree(instance->pdata);
instance->pdata = NULL;

17
src/signer/signer.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _SIGNER_H
#define _SIGNER_H
#include <opensc.h>
#include <opensc-pkcs15.h>
typedef struct _PluginInstance
{
char *signdata;
int signdata_len;
struct sc_context *ctx;
struct sc_card *card;
struct sc_pkcs15_card *p15card;
} PluginInstance;
#endif

50
src/signer/testprog.c Normal file
View File

@ -0,0 +1,50 @@
#include <opensc.h>
#include <opensc-pkcs15.h>
#include <openssl/pkcs7.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include "opensc-support.h"
#include "opensc-crypto.h"
#include "signer.h"
int test()
{
BIO *in;
PKCS7 *p7;
in = BIO_new_file("sample.pem", "r");
p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
if (p7 == NULL) {
goto err;
}
// return prp7(p7);
return 0;
err:
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
return 1;
}
int main()
{
PluginInstance pl;
u8 *data;
int datalen, r;
#if 0
test();
return 0;
#endif
pl.signdata = strdup("12345\nMoro moro, mitä poro\nTesting 1234567890");
pl.signdata_len = strlen(pl.signdata);
r = create_envelope(&pl, &data, &datalen);
if (r) {
printf("create_env() failed\n");
return 1;
}
return 0;
}