Branch: master

68dc59cb 2015-09-19 16:17:20 Timothy Pearson
Add autoPIN support
M src/cardpincheck.c
diff --git a/src/cardpincheck.c b/src/cardpincheck.c
index c79012b..e6c1cc4 100644
--- a/src/cardpincheck.c
+++ b/src/cardpincheck.c
@@ -18,9 +18,11 @@
 #include <stdio.h>
 #include <termios.h>
 #include <unistd.h>
+#include <string.h>
 
 #include <pkcs11-helper-1.0/pkcs11h-certificate.h>
 #include <pkcs11-helper-1.0/pkcs11h-openssl.h>
+#include <openssl/x509v3.h>
 
 #define CARD_MAX_LOGIN_RETRY_COUNT 3
 
@@ -82,7 +84,7 @@
 		if (cached_pin) {
 			free(cached_pin);
 		}
-		cached_pin= malloc(sizeof(char) * pin_max);
+		cached_pin = malloc(sizeof(char) * pin_max);
 		snprintf(cached_pin, pin_max, "%s", line);
 
 		// Copy PIN to buffer
@@ -100,6 +102,68 @@
 		vfprintf(stderr, format, args);
 		fprintf(stderr, "\n");
 	}
+}
+
+char* tde_autopin(X509* x509_cert) {
+	char* retString = NULL;
+	int i;
+
+	// Use subjAltName field in card certificate to provide the card's PIN,
+	// in order to support optional pin-less operation.
+	// Parse the TDE autologin extension
+	// Structure:
+	// OID 1.3.6.1.4.1.40364.1.2.1
+	// 	SEQUENCE
+	// 		ASN1_CONSTRUCTED [index: 0] (field name: pin)
+	// 			GeneralString
+
+	// Register custom OID type for TDE autopin data
+	ASN1_OBJECT* tde_autopin_data_object = OBJ_txt2obj("1.3.6.1.4.1.40364.1.2.1", 0);
+
+	GENERAL_NAMES* subjectAltNames = (GENERAL_NAMES*)X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL);
+	int altNameCount = sk_GENERAL_NAME_num(subjectAltNames);
+	for (i=0; i < altNameCount; i++) {
+		GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
+		if (generalName->type == GEN_OTHERNAME) {
+			OTHERNAME* otherName = generalName->d.otherName;
+			if (!OBJ_cmp(otherName->type_id, tde_autopin_data_object)) {
+				ASN1_TYPE* asnValue = otherName->value;
+				if (asnValue) {
+					// Found autopin structure
+					int index;
+					ASN1_TYPE* asnSeqValue = NULL;
+					ASN1_GENERALSTRING* asnGeneralString = NULL;
+					STACK_OF(ASN1_TYPE) *asnSeqValueStack = NULL;
+					long asn1SeqValueObjectLength;
+					int asn1SeqValueObjectTag;
+					int asn1SeqValueObjectClass;
+					int returnCode;
+
+					index = 0;	// Search for the PIN field
+					asnSeqValueStack = ASN1_seq_unpack_ASN1_TYPE(ASN1_STRING_data(asnValue->value.sequence), ASN1_STRING_length(asnValue->value.sequence), d2i_ASN1_TYPE, ASN1_TYPE_free);
+					asnSeqValue = sk_ASN1_TYPE_value(asnSeqValueStack, index);
+					if (asnSeqValue) {
+						if (asnSeqValue->value.octet_string->data[0] == ((V_ASN1_CONSTRUCTED | V_ASN1_CONTEXT_SPECIFIC) + index)) {
+							const unsigned char* asn1SeqValueObjectData = asnSeqValue->value.sequence->data;
+							returnCode = ASN1_get_object(&asn1SeqValueObjectData, &asn1SeqValueObjectLength, &asn1SeqValueObjectTag, &asn1SeqValueObjectClass, asnSeqValue->value.sequence->length);
+							if (!(returnCode & 0x80)) {
+								if (returnCode == (V_ASN1_CONSTRUCTED + index)) {
+									if (d2i_ASN1_GENERALSTRING(&asnGeneralString, &asn1SeqValueObjectData, asn1SeqValueObjectLength) != NULL) {
+										retString = strdup(ASN1_STRING_data(asnGeneralString));
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// Clean up
+	OBJ_cleanup();
+
+	return retString;
 }
 
 int main(int argc, char* argv[]) {
@@ -203,6 +267,13 @@
 			ret = -1;
 		}
 
+		// Check for TDE autopin structure
+		char* autopin = tde_autopin(x509_local);
+		if (autopin) {
+			cached_pin = autopin;
+			use_cached_pin = 1;
+		}
+
 		// Extract public key from X509 certificate
 		EVP_PKEY* x509_pubkey = NULL;
 		x509_pubkey = X509_get_pubkey(x509_local);