From 010debef6111c6776cda7ad8d00737f2d1dbb164 Mon Sep 17 00:00:00 2001 From: Robert Relyea Date: Tue, 28 Jun 2011 17:28:22 +0200 Subject: [PATCH 1/7] libcacard/vcard_emul_nss: support cards lying about CKM_RSA_X_509 support Some tokens claim to do CKM_RSA_X_509, but then choke when they try to do the actual operations. Try to detect those cases and treat them as if the token didn't claim support for X_509. Signed-off-by: Robert Relyea --- libcacard/vcard_emul_nss.c | 133 +++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 6 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index f3db657d74..0f5095405f 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -33,10 +33,17 @@ #include "vreader.h" #include "vevent.h" +typedef enum { + VCardEmulUnknown = -1, + VCardEmulFalse = 0, + VCardEmulTrue = 1 +} VCardEmulTriState; + struct VCardKeyStruct { CERTCertificate *cert; PK11SlotInfo *slot; SECKEYPrivateKey *key; + VCardEmulTriState failedX509; }; @@ -140,6 +147,7 @@ vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) /* NOTE: the cert is a temp cert, not necessarily the cert in the token, * use the DER version of this function */ key->key = PK11_FindKeyByDERCert(slot, cert, NULL); + key->failedX509 = VCardEmulUnknown; return key; } @@ -208,13 +216,23 @@ vcard_emul_rsa_op(VCard *card, VCardKey *key, { SECKEYPrivateKey *priv_key; unsigned signature_len; + PK11SlotInfo *slot; SECStatus rv; + unsigned char buf[2048]; + unsigned char *bp = NULL; + int pad_len; + vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS; if ((!nss_emul_init) || (key == NULL)) { /* couldn't get the key, indicate that we aren't logged in */ return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; } priv_key = vcard_emul_get_nss_key(key); + if (priv_key == NULL) { + /* couldn't get the key, indicate that we aren't logged in */ + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; + } + slot = vcard_emul_card_get_slot(card); /* * this is only true of the rsa signature @@ -223,13 +241,116 @@ vcard_emul_rsa_op(VCard *card, VCardKey *key, if (buffer_size != signature_len) { return VCARD7816_STATUS_ERROR_DATA_INVALID; } - rv = PK11_PrivDecryptRaw(priv_key, buffer, &signature_len, signature_len, - buffer, buffer_size); - if (rv != SECSuccess) { - return vcard_emul_map_error(PORT_GetError()); + /* be able to handle larger keys if necessariy */ + bp = &buf[0]; + if (sizeof(buf) < signature_len) { + bp = qemu_malloc(signature_len); } - assert(buffer_size == signature_len); - return VCARD7816_STATUS_SUCCESS; + + /* + * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then + * choke when they try to do the actual operations. Try to detect + * those cases and treat them as if the token didn't claim support for + * X_509. + */ + if (key->failedX509 != VCardEmulTrue + && PK11_DoesMechanism(slot, CKM_RSA_X_509)) { + rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len, + buffer, buffer_size); + if (rv == SECSuccess) { + assert(buffer_size == signature_len); + memcpy(buffer, bp, signature_len); + key->failedX509 = VCardEmulFalse; + goto cleanup; + } + /* + * we've had a successful X509 operation, this failure must be + * somethine else + */ + if (key->failedX509 == VCardEmulFalse) { + ret = vcard_emul_map_error(PORT_GetError()); + goto cleanup; + } + /* + * key->failedX509 must be Unknown at this point, try the + * non-x_509 case + */ + } + /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */ + /* is this a PKCS #1 formatted signature? */ + if ((buffer[0] == 0) && (buffer[1] == 1)) { + int i; + + for (i = 2; i < buffer_size; i++) { + /* rsa signature pad */ + if (buffer[i] != 0xff) { + break; + } + } + if ((i < buffer_size) && (buffer[i] == 0)) { + /* yes, we have a properly formated PKCS #1 signature */ + /* + * NOTE: even if we accidentally got an encrypt buffer, which + * through shear luck started with 00, 01, ff, 00, it won't matter + * because the resulting Sign operation will effectively decrypt + * the real buffer. + */ + SECItem signature; + SECItem hash; + + i++; + hash.data = &buffer[i]; + hash.len = buffer_size - i; + signature.data = bp; + signature.len = signature_len; + rv = PK11_Sign(priv_key, &signature, &hash); + if (rv != SECSuccess) { + ret = vcard_emul_map_error(PORT_GetError()); + goto cleanup; + } + assert(buffer_size == signature.len); + memcpy(buffer, bp, signature.len); + /* + * we got here because either the X509 attempt failed, or the + * token couldn't do the X509 operation, in either case stay + * with the PKCS version for future operations on this key + */ + key->failedX509 = VCardEmulTrue; + goto cleanup; + } + } + pad_len = buffer_size - signature_len; + assert(pad_len < 4); + /* + * OK now we've decrypted the payload, package it up in PKCS #1 for the + * upper layer. + */ + buffer[0] = 0; + buffer[1] = 2; /* RSA_encrypt */ + pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */ + /* + * padding for PKCS #1 encrypted data is a string of random bytes. The + * random butes protect against potential decryption attacks against RSA. + * Since PrivDecrypt has already stripped those bytes, we can't reconstruct + * them. This shouldn't matter to the upper level code which should just + * strip this code out anyway, so We'll pad with a constant 3. + */ + memset(&buffer[2], 0x03, pad_len); + pad_len += 2; /* index to the end of the pad */ + buffer[pad_len] = 0; + pad_len++; /* index to the start of the data */ + memcpy(&buffer[pad_len], bp, signature_len); + /* + * we got here because either the X509 attempt failed, or the + * token couldn't do the X509 operation, in either case stay + * with the PKCS version for future operations on this key + */ + key->failedX509 = VCardEmulTrue; +cleanup: + if (bp != buf) { + qemu_free(bp); + } + return ret; } /* From ee83d41466ab393d82d9abf57b9ec24d4e6633be Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 4 Jul 2011 18:10:43 +0200 Subject: [PATCH 2/7] libcacard: don't leak vcard_emul_alloc_arrays mem vcard_emul_mirror_card and vcard_emul_init use vcard_emul_alloc_arrays to allocate memory for temporary arrays which will contain elements that in the end will be used one by one in cac_card_init. The arrays themselves are never stored anywhere, they are only used as temporary containers. Hence the memory that was allocated for these arrays should be freed after use or they will be leaked. --- libcacard/vcard_emul_nss.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 0f5095405f..f1763f55f7 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -597,6 +597,7 @@ vcard_emul_mirror_card(VReader *vreader) VCardKey **keys; PK11SlotInfo *slot; PRBool ret; + VCard *card; slot = vcard_emul_reader_get_slot(vreader); if (slot == NULL) { @@ -656,7 +657,12 @@ vcard_emul_mirror_card(VReader *vreader) } /* now create the card */ - return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); + card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); + qemu_free(certs); + qemu_free(cert_len); + qemu_free(keys); + + return card; } static VCardEmulType default_card_type = VCARD_EMUL_NONE; @@ -941,6 +947,9 @@ vcard_emul_init(const VCardEmulOptions *options) vreader_free(vreader); has_readers = PR_TRUE; } + qemu_free(certs); + qemu_free(cert_len); + qemu_free(keys); } /* if we aren't suppose to use hw, skip looking up hardware tokens */ From 009651675afc775fc77018273a47fb36c28a8100 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 22 Jul 2011 13:42:17 +0200 Subject: [PATCH 3/7] libcacard: s/strip(args++)/strip(args+1) vcard_emul_options used args = strip(args++) a few times, which was not returning the expected result since the rest of the code expected args to be increased by at least 1, which is not the case if *args is not a blank space when this function is called. Replace these calls by "strip(args+1)" which will do what we expect. Signed-off-by: Christophe Fergeau Reviewed-by: Alon Levy --- libcacard/vcard_emul_nss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index f1763f55f7..8c59eff81d 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -1171,7 +1171,7 @@ vcard_emul_options(const char *args) args++; continue; } - args = strip(args++); + args = strip(args+1); type_params = args; args = strpbrk(args + 1, ",)"); if (*args == 0) { @@ -1182,7 +1182,7 @@ vcard_emul_options(const char *args) continue; } type_params_length = args - name; - args = strip(args++); + args = strip(args+1); if (*args == 0) { break; } From a5aa842a0597ef9a24e80966b02ca01f287fb334 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 22 Jul 2011 13:42:18 +0200 Subject: [PATCH 4/7] libcacard: fix soft=... parsing in vcard_emul_options The previous parser had copy and paste errors when computing vname_length and type_params_length, "name" was used instead of respectively vname and type_params. This led to length that could be bigger than the input string, and to access out of the array bounds when trying to copy these strings. valgrind rightfully complained about this. It also didn't handle empty fields correctly, Signed-off-by: Christophe Fergeau Reviewed-by: Alon Levy --- libcacard/vcard_emul_nss.c | 81 ++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 8c59eff81d..3360f6c22f 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -1110,8 +1110,6 @@ vcard_emul_options(const char *args) { int reader_count = 0; VCardEmulOptions *opts; - char type_str[100]; - int type_len; /* Allow the future use of allocating the options structure on the fly */ memcpy(&options, &default_options, sizeof(options)); @@ -1126,43 +1124,23 @@ vcard_emul_options(const char *args) * cert_2,cert_3...) */ if (strncmp(args, "soft=", 5) == 0) { const char *name; + size_t name_length; const char *vname; + size_t vname_length; const char *type_params; + size_t type_params_length; + char type_str[100]; VCardEmulType type; - int name_length, vname_length, type_params_length, count, i; + int count, i; VirtualReaderOptions *vreaderOpt = NULL; args = strip(args + 5); if (*args != '(') { continue; } + args = strip(args+1); + name = args; - args = strpbrk(args + 1, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - args = strip(args+1); - name_length = args - name - 2; - vname = args; - args = strpbrk(args + 1, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - vname_length = args - name - 2; - args = strip(args+1); - type_len = strpbrk(args, ",)") - args; - assert(sizeof(type_str) > type_len); - strncpy(type_str, args, type_len); - type_str[type_len] = 0; - type = vcard_emul_type_from_string(type_str); args = strpbrk(args, ",)"); if (*args == 0) { break; @@ -1171,9 +1149,11 @@ vcard_emul_options(const char *args) args++; continue; } + name_length = args - name; args = strip(args+1); - type_params = args; - args = strpbrk(args + 1, ",)"); + + vname = args; + args = strpbrk(args, ",)"); if (*args == 0) { break; } @@ -1181,8 +1161,38 @@ vcard_emul_options(const char *args) args++; continue; } - type_params_length = args - name; + vname_length = args - vname; args = strip(args+1); + + type_params = args; + args = strpbrk(args, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + type_params_length = args - type_params; + args = strip(args+1); + + type_params_length = MIN(type_params_length, sizeof(type_str)-1); + strncpy(type_str, type_params, type_params_length); + type_str[type_params_length] = 0; + type = vcard_emul_type_from_string(type_str); + + type_params = args; + args = strpbrk(args, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + type_params_length = args - type_params; + args = strip(args+1); + if (*args == 0) { break; } @@ -1202,13 +1212,14 @@ vcard_emul_options(const char *args) vreaderOpt->card_type = type; vreaderOpt->type_params = copy_string(type_params, type_params_length); - count = count_tokens(args, ',', ')'); + count = count_tokens(args, ',', ')') + 1; vreaderOpt->cert_count = count; vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *)); for (i = 0; i < count; i++) { - const char *cert = args + 1; - args = strpbrk(args + 1, ",)"); + const char *cert = args; + args = strpbrk(args, ",)"); vreaderOpt->cert_name[i] = copy_string(cert, args - cert); + args = strip(args+1); } if (*args == ')') { args++; From d246b3cfd5378e45895b0834a8b8762733c0148f Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 22 Jul 2011 13:42:19 +0200 Subject: [PATCH 5/7] libcacard: introduce NEXT_TOKEN macro vcard_emul_options now has repetitive code to read the current token and advance to the next. After the previous changes, this repetitive code can be moved in a NEXT_TOKEN macro to avoid having this code duplicated. Signed-off-by: Christophe Fergeau Reviewed-by: Alon Levy --- libcacard/vcard_emul_nss.c | 71 +++++++++++++------------------------- 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 3360f6c22f..1a24acf645 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -1105,6 +1105,26 @@ find_blank(const char *str) static VCardEmulOptions options; #define READER_STEP 4 +/* Expects "args" to be at the beginning of a token (ie right after the ',' + * ending the previous token), and puts the next token start in "token", + * and its length in "token_length". "token" will not be nul-terminated. + * After calling the macro, "args" will be advanced to the beginning of + * the next token. + * This macro may call continue or break. + */ +#define NEXT_TOKEN(token) \ + (token) = args; \ + args = strpbrk(args, ",)"); \ + if (*args == 0) { \ + break; \ + } \ + if (*args == ')') { \ + args++; \ + continue; \ + } \ + (token##_length) = args - (token); \ + args = strip(args+1); + VCardEmulOptions * vcard_emul_options(const char *args) { @@ -1140,58 +1160,15 @@ vcard_emul_options(const char *args) } args = strip(args+1); - name = args; - args = strpbrk(args, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - name_length = args - name; - args = strip(args+1); - - vname = args; - args = strpbrk(args, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - vname_length = args - vname; - args = strip(args+1); - - type_params = args; - args = strpbrk(args, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - type_params_length = args - type_params; - args = strip(args+1); - + NEXT_TOKEN(name) + NEXT_TOKEN(vname) + NEXT_TOKEN(type_params) type_params_length = MIN(type_params_length, sizeof(type_str)-1); strncpy(type_str, type_params, type_params_length); type_str[type_params_length] = 0; type = vcard_emul_type_from_string(type_str); - type_params = args; - args = strpbrk(args, ",)"); - if (*args == 0) { - break; - } - if (*args == ')') { - args++; - continue; - } - type_params_length = args - type_params; - args = strip(args+1); + NEXT_TOKEN(type_params) if (*args == 0) { break; From 2b56cb87e46fbfc5dca31ed13ffc9a5422e1e405 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 22 Jul 2011 13:42:20 +0200 Subject: [PATCH 6/7] libcacard: replace copy_string with strndup copy_string reimplements strndup, this commit removes it and replaces all copy_string uses with strndup. Signed-off-by: Christophe Fergeau Reviewed-by: Alon Levy --- libcacard/vcard_emul_nss.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 1a24acf645..84fc49026f 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -1055,17 +1055,6 @@ vcard_emul_replay_insertion_events(void) /* * Silly little functions to help parsing our argument string */ -static char * -copy_string(const char *str, int str_len) -{ - char *new_str; - - new_str = qemu_malloc(str_len+1); - memcpy(new_str, str, str_len); - new_str[str_len] = 0; - return new_str; -} - static int count_tokens(const char *str, char token, char token_end) { @@ -1184,18 +1173,18 @@ vcard_emul_options(const char *args) } opts->vreader = vreaderOpt; vreaderOpt = &vreaderOpt[opts->vreader_count]; - vreaderOpt->name = copy_string(name, name_length); - vreaderOpt->vname = copy_string(vname, vname_length); + vreaderOpt->name = qemu_strndup(name, name_length); + vreaderOpt->vname = qemu_strndup(vname, vname_length); vreaderOpt->card_type = type; vreaderOpt->type_params = - copy_string(type_params, type_params_length); + qemu_strndup(type_params, type_params_length); count = count_tokens(args, ',', ')') + 1; vreaderOpt->cert_count = count; vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *)); for (i = 0; i < count; i++) { const char *cert = args; args = strpbrk(args, ",)"); - vreaderOpt->cert_name[i] = copy_string(cert, args - cert); + vreaderOpt->cert_name[i] = qemu_strndup(cert, args - cert); args = strip(args+1); } if (*args == ')') { @@ -1222,7 +1211,7 @@ vcard_emul_options(const char *args) args = strip(args+10); params = args; args = find_blank(args); - opts->hw_type_params = copy_string(params, args-params); + opts->hw_type_params = qemu_strndup(params, args-params); /* db="/data/base/path" */ } else if (strncmp(args, "db=", 3) == 0) { const char *db; @@ -1233,7 +1222,7 @@ vcard_emul_options(const char *args) args++; db = args; args = strpbrk(args, "\"\n"); - opts->nss_db = copy_string(db, args-db); + opts->nss_db = qemu_strndup(db, args-db); if (*args != 0) { args++; } From 0f94d6da357954857f95d5be69817d8551a5526f Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 27 Jun 2011 11:58:20 +0200 Subject: [PATCH 7/7] libcacard: add pc file, install it + includes Additionally: + add --includedir configure parameters + make install-libcacard install vscclient as well --- configure | 5 +++++ libcacard/Makefile | 27 ++++++++++++++++++++++++--- libcacard/libcacard.pc.in | 13 +++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 libcacard/libcacard.pc.in diff --git a/configure b/configure index e57efb179c..1cc376703c 100755 --- a/configure +++ b/configure @@ -146,6 +146,7 @@ datadir="\${prefix}/share/qemu" docdir="\${prefix}/share/doc/qemu" bindir="\${prefix}/bin" libdir="\${prefix}/lib" +includedir="\${prefix}/include" sysconfdir="\${prefix}/etc" confsuffix="/qemu" slirp="yes" @@ -539,6 +540,8 @@ for opt do ;; --libdir=*) libdir="$optarg" ;; + --includedir=*) includedir="$optarg" + ;; --datadir=*) datadir="$optarg" ;; --docdir=*) docdir="$optarg" @@ -2542,6 +2545,7 @@ echo "Install prefix $prefix" echo "BIOS directory `eval echo $datadir`" echo "binary directory `eval echo $bindir`" echo "library directory `eval echo $libdir`" +echo "include directory `eval echo $includedir`" echo "config directory `eval echo $sysconfdir`" if test "$mingw32" = "no" ; then echo "Manual directory `eval echo $mandir`" @@ -2635,6 +2639,7 @@ echo all: >> $config_host_mak echo "prefix=$prefix" >> $config_host_mak echo "bindir=$bindir" >> $config_host_mak echo "libdir=$libdir" >> $config_host_mak +echo "includedir=$includedir" >> $config_host_mak echo "mandir=$mandir" >> $config_host_mak echo "datadir=$datadir" >> $config_host_mak echo "sysconfdir=$sysconfdir" >> $config_host_mak diff --git a/libcacard/Makefile b/libcacard/Makefile index 9802c37ee8..bc34bf2449 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -2,7 +2,10 @@ -include $(SRC_PATH)/Makefile.objs -include $(SRC_PATH)/rules.mak -$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard) +libcacard_srcpath=$(SRC_PATH)/libcacard +libcacard_includedir=$(includedir)/cacard + +$(call set-vpath, $(SRC_PATH):$(libcacard_srcpath)) # objects linked against normal qemu binaries, not compiled with libtool QEMU_OBJS=$(addprefix ../,$(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(trace-obj-y)) @@ -18,7 +21,7 @@ vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $@") clean: - rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la + rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la *.pc rm -Rf .libs all: vscclient @@ -36,7 +39,25 @@ else libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB) $(call quiet-command,libtool --mode=link --quiet --tag=CC $(CC) $(libcacard_libs) -lrt -rpath $(libdir) -o $@ $^," lt LINK $@") -install-libcacard: libcacard.la +libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in + sed -e 's|@LIBDIR@|$(libdir)|' \ + -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \ + -e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \ + -e 's|@PREFIX@|$(prefix)|' \ + < $(libcacard_srcpath)/libcacard.pc.in > libcacard.pc + +.PHONY: install-libcacard + +install-libcacard: libcacard.pc libcacard.la vscclient $(INSTALL_DIR) "$(DESTDIR)$(libdir)" + $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig" + $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)" + $(INSTALL_DIR) "$(DESTDIR)$(bindir)" + libtool --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)" libtool --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)" + libtool --mode=install $(INSTALL_PROG) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" + for inc in *.h; do \ + libtool --mode=install $(INSTALL_PROG) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ + done + endif diff --git a/libcacard/libcacard.pc.in b/libcacard/libcacard.pc.in new file mode 100644 index 0000000000..b6859b0c1f --- /dev/null +++ b/libcacard/libcacard.pc.in @@ -0,0 +1,13 @@ +prefix=@PREFIX@ +exec_prefix=${prefix} +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: cacard +Description: CA Card library +Version: @VERSION@ + +Requires: nss +Libs: -L${libdir} -lcacard +Libs.private: +Cflags: -I${includedir}