Add very preliminary and quick port of an old scam

code that implements ldap-authentication support,
needs to be rewritten for more specific OpenSC
usage some other day.

Work in progress, only tested with FINEID cards.


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1431 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
aet 2003-09-09 15:00:51 +00:00
parent 09f2d373b2
commit 1ea97fbb5e
1 changed files with 206 additions and 19 deletions

View File

@ -24,13 +24,13 @@
#endif
#if defined(HAVE_OPENSSL) && defined(HAVE_LDAP)
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/x509.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
@ -38,20 +38,27 @@
#include <opensc/pkcs15.h>
#include <opensc/scldap.h>
#include <opensc/scrandom.h>
#include <opensc/log.h>
#include "cert_support.h"
#include "scam.h"
typedef struct _scam_method_data {
struct sc_context *ctx;
struct sc_card *card;
struct sc_pkcs15_card *p15card;
scldap_context *lctx;
int card_locked;
struct sc_pkcs15_object *objs[32];
struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_object *prkey, *pin;
scldap_context *lctx;
char *scldap_entry;
} scam_method_data;
#define MAX_PATHLEN 10
#define MAX_ENTRYLEN 256
const char *p15_ldap_usage(void)
{
static char buf[500];
@ -180,6 +187,11 @@ int p15_ldap_init(scam_context * sctx, int argc, const char **argv)
return SCAM_FAILED;
}
scldap_parse_arguments(&data->lctx, argc, argv);
data->scldap_entry = (char *) malloc(MAX_ENTRYLEN);
if (!data->scldap_entry) {
return SCAM_FAILED;
}
memset(data->scldap_entry, 0, MAX_ENTRYLEN);
return SCAM_SUCCESS;
}
@ -212,41 +224,211 @@ int p15_ldap_qualify(scam_context * sctx, unsigned char *password)
return SCAM_SUCCESS;
}
static int copy_result(scldap_result * lresult, unsigned char **result, unsigned long *resultlen)
{
if (!lresult)
return -1;
*result = NULL;
*resultlen = 0;
*result = (unsigned char *) malloc(lresult->result[0].datalen + 1);
if (!*result)
return -1;
memset(*result, 0, lresult->result[0].datalen + 1);
memcpy(*result, lresult->result[0].data, lresult->result[0].datalen);
*resultlen = lresult->result[0].datalen;
return 0;
}
static void modify_base(scam_context * sctx, const char *entry, char *dn)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
char approx_entry[MAX_ENTRYLEN];
int entrynum = -1;
if (!sctx || !entry || !dn)
return;
entrynum = scldap_get_entry(data->lctx, entry);
if (entrynum < 0) {
return;
}
snprintf(approx_entry, MAX_ENTRYLEN, "%s %s approx base", data->p15card->label, data->p15card->manufacturer_id);
if (scldap_approx_base_by_dn(data->lctx, approx_entry, dn, &data->lctx->entry[entrynum].base) < 0) {
return;
}
sc_debug(data->ctx, "modify_base: %s\n", data->lctx->entry[entrynum].base);
}
int p15_ldap_auth(scam_context * sctx, int argc, const char **argv,
const char *user, const char *password)
{
scam_method_data *data = (scam_method_data *) sctx->method_data;
struct sc_pkcs15_cert *p15cert = NULL;
scCertificate *CardCert = NULL, *Cert = NULL, *CACerts[MAX_PATHLEN];
X509 *currcert = NULL;
u8 random_data[20], chg[256];
int r, err = SCAM_FAILED, chglen;
EVP_PKEY *pubkey = NULL;
X509 *cert = NULL;
unsigned char *ptr = NULL;
scldap_result *lresult = NULL;
int r = 0, i = 0, err = SCAM_FAILED, chglen;
if (!sctx->method_data) {
return SCAM_FAILED;
}
for (i = 0; i < MAX_PATHLEN; i++) {
CACerts[i] = NULL;
}
Cert = certAlloc();
if (!Cert) {
goto end;
}
CardCert = certAlloc();
if (!CardCert) {
goto end;
}
r = sc_pkcs15_read_certificate(data->p15card, data->cinfo, &p15cert);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_read_certificate: %s\n", sc_strerror(r));
goto end;
}
cert = X509_new();
ptr = p15cert->data;
if (!d2i_X509(&cert, &ptr, p15cert->data_len)) {
scam_log_msg(sctx, "Invalid certificate. (user %s)\n", user);
/* FIXME */
CardCert->len = p15cert->data_len;
CardCert->buf = (unsigned char *) malloc(CardCert->len);
if (!CardCert->buf) {
scam_print_msg(sctx, "out of memory\n", sc_strerror(r));
goto end;
}
pubkey = X509_get_pubkey(cert);
if (!pubkey || pubkey->type != EVP_PKEY_RSA) {
memcpy(CardCert->buf, p15cert->data, p15cert->data_len);
/* Parse user certificate just once into a x509 structure
and not for each individual operation */
if (!(CardCert->cert = certParseCertificate(CardCert->buf, CardCert->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid certificate.\n");
goto end;
}
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s auth certificate", data->p15card->label, data->p15card->manufacturer_id);
modify_base(sctx, data->scldap_entry, certGetSubject(CardCert->cert));
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, user);
if ((r < 0) || (copy_result(lresult, &Cert->buf, &Cert->len) < 0)) {
scam_print_msg(sctx, "Search failed: no auth certificate found.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
if (memcmp(CardCert->buf, Cert->buf, Cert->len) != 0) {
scam_print_msg(sctx, "Certificate comparing failed.\n");
goto end;
}
certFree(CardCert);
CardCert = NULL;
/* Parse user certificate just once into a x509 structure
and not for each individual operation */
if (!(Cert->cert = certParseCertificate(Cert->buf, Cert->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid certificate.\n");
goto end;
}
/* Do not accept self signed user certificates or certificates
without issuer or subject fields */
if (certIsSelfSigned(Cert->cert) != 0) {
scam_print_msg(sctx, "certIsSelfSigned failed: certificate is not signed by a CA.\n");
goto end;
}
/* We want an encipherment key */
if ((r = certCheckKeyUsage(Cert->cert, DATA_ENCIPHERMENT)) < 1) {
scam_print_msg(sctx, "certCheckKeyUsage failed: certificate cannot be used for encipherment.\n");
if (r == -1) {
scam_log_msg(sctx, "KeyUsage check failed (user %s).\n", user);
} else {
scam_log_msg(sctx, "Wrong certificate type (user %s).\n", user);
}
goto end;
}
if (!(Cert->pubkey = certParsePublicKey(Cert->cert))) {
scam_print_msg(sctx, "certParsePublicKey failed: invalid public key in certificate.\n");
scam_log_msg(sctx, "Invalid public key (user %s).\n", user);
goto end;
}
if (Cert->pubkey->type != EVP_PKEY_RSA) {
scam_log_msg(sctx, "Invalid public key. (user %s)\n", user);
goto end;
}
chglen = RSA_size(pubkey->pkey.rsa);
chglen = RSA_size(Cert->pubkey->pkey.rsa);
if (chglen > sizeof(chg)) {
scam_print_msg(sctx, "RSA key too big.\n");
goto end;
}
/* Parse issuer from each one certificate
in turn when you get them from the LDAP serer and stuff them
all into the chain when we have other certificates than FINEID
until issuer == subject. */
do {
char *distpoint = NULL;
/* Find empty slot */
for (i = 0; i < MAX_PATHLEN; i++) {
if (!(CACerts[i])) {
break;
}
}
/* Path length exceeded */
if (i == MAX_PATHLEN) {
goto end;
}
CACerts[i] = certAlloc();
if (!(CACerts[i])) {
goto end;
}
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s ca certificate", data->p15card->label, data->p15card->manufacturer_id);
modify_base(sctx, data->scldap_entry, certGetIssuer(Cert->cert));
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, NULL);
if ((r < 0) || (copy_result(lresult, &CACerts[i]->buf, &CACerts[i]->len) < 0)) {
scam_print_msg(sctx, "Search failed: no CA certificate.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
/* Parse CA certificate into a x509 structure */
if (!(CACerts[i]->cert = certParseCertificate(CACerts[i]->buf, CACerts[i]->len))) {
scam_print_msg(sctx, "certParseCertificate failed: invalid CA certificate.\n");
goto end;
}
distpoint = certGetCRLDistributionPoint(Cert->cert);
snprintf(data->scldap_entry, MAX_ENTRYLEN, "%s %s crl", data->p15card->label, data->p15card->manufacturer_id);
if (scldap_is_valid_url(distpoint)) {
if (scldap_url_to_entry(data->lctx, data->scldap_entry, distpoint) < 0) {
scam_print_msg(sctx, "scldap_url_to_entry failed: invalid CRL.\n");
free(distpoint);
distpoint = NULL;
goto end;
}
}
free(distpoint);
distpoint = NULL;
r = scldap_search(data->lctx, data->scldap_entry, &lresult, 1, NULL);
if ((r < 0) || (copy_result(lresult, &CACerts[i]->crlbuf, &CACerts[i]->crllen) < 0)) {
scam_print_msg(sctx, "Search failed: CRL not found.\n");
goto end;
}
scldap_free_result(lresult);
lresult = NULL;
if (!(CACerts[i]->crl = certParseCRL(CACerts[i]->crlbuf, CACerts[i]->crllen))) {
scam_print_msg(sctx, "certParseCRL failed: invalid CRL.\n");
scam_log_msg(sctx, "Could not parse CA CRL.\n");
goto end;
}
currcert = CACerts[i]->cert;
} while (!certIsSelfSigned(currcert));
if ((r = certVerifyCAChain(CACerts, Cert->cert)) != 0) {
scam_print_msg(sctx, "certVerifyCAChain failed: certificate has invalid information.\n");
scam_log_msg(sctx, "certVerifyCAChain failed: %s.\n", certError((unsigned long) r));
goto end;
}
certFreeAll(CACerts);
r = scrandom_get_data(random_data, sizeof(random_data));
if (r < 0) {
scam_log_msg(sctx, "scrandom_get_data failed.\n");
@ -277,17 +459,18 @@ int p15_ldap_auth(scam_context * sctx, int argc, const char **argv,
goto end;
}
r = RSA_verify(NID_sha1, random_data, 20, chg, chglen, pubkey->pkey.rsa);
r = RSA_verify(NID_sha1, random_data, 20, chg, chglen, Cert->pubkey->pkey.rsa);
if (r != 1) {
scam_print_msg(sctx, "Signature verification failed.\n");
goto end;
}
err = SCAM_SUCCESS;
end:
if (pubkey)
EVP_PKEY_free(pubkey);
if (cert)
X509_free(cert);
if (CardCert)
certFree(CardCert);
if (Cert)
certFree(Cert);
certFreeAll(CACerts);
if (p15cert)
sc_pkcs15_free_certificate(p15cert);
return err;
@ -300,6 +483,10 @@ void p15_ldap_deinit(scam_context * sctx)
if (!sctx->method_data) {
return;
}
if (data->scldap_entry) {
free(data->scldap_entry);
}
data->scldap_entry = NULL;
if (data->lctx) {
scldap_free_parameters(data->lctx);
}