--- src/lib/yubikey_db.h.orig	2008-08-03 13:27:03.000000000 +0200
+++ src/lib/yubikey_db.h	2009-04-01 14:43:04.000000000 +0200
@@ -29,6 +29,7 @@
 #define YKDB_MAGIC_SIZE		4
 #define YKDB_VERSION		0x01
 #define YKDB_KEY_BYTE_SIZE	16
+#define YKDB_PIN_SIZE		4	/* Size of optional PIN code */
 
 #define YKDB_SUCCESS		0
 #define YKDB_ERR_ARGS		1
@@ -38,9 +39,10 @@
 #define YKDB_ERR_DB_INV		5
 #define YKDB_ERR_DB_EMPTY	6
 
-#define YKDB_TOKEN_ENC_PUBLIC_UID	0x01
-#define YKDB_TOKEN_ENC_PASSWORD		0x02
-#define YKDB_TOKEN_STATIC			0x04
+#define YKDB_TOKEN_ENC_PUBLIC_UID	0x01 // 0000 0001
+#define YKDB_TOKEN_ENC_PASSWORD		0x02 // 0000 0010
+#define YKDB_TOKEN_STATIC		0x04 // 0000 0100
+#define YKDB_TOKEN_PIN			0x08 // 0000 1000
 
 extern int ykdb_errno;
 
--- src/utils/ykpasswd.c.orig	2008-09-24 09:55:24.000000000 +0200
+++ src/utils/ykpasswd.c	2009-04-01 14:42:39.000000000 +0200
@@ -24,6 +24,8 @@
 #include "config.h"
 #endif
 
+#define	DEBUG 1
+
 #include <getopt.h>
 #include <pwd.h>
 #include <stdio.h>
@@ -40,6 +42,7 @@
 int						amroot;
 
 char					*otp;
+char					*pin;
 char					*user_text;
 char					*public_uid_text = NULL;
 uint8_t					public_uid_bin[PUBLIC_UID_BYTE_SIZE];
@@ -215,6 +218,8 @@
 	/* free any and all allocated memory */
 	if (otp)
 		free(otp);
+	if (pin)
+		free(pin);
 
 	if (user_text)
 		free(user_text);
@@ -255,6 +260,7 @@
     fprintf(stdout, "   -f <uid>    Fixed (Public) UID in hex\n");
     fprintf(stdout, "   -k <key>    AES key in hex\n");
     fprintf(stdout, "   -o <otp>    Yubikey generated OTP\n");
+    fprintf(stdout, "   -i <pin>    Your PIN code\n");
     fprintf(stdout, "   -p <uid>    Private UID in hex\n");
 //    fprintf(stdout, "   -s          Sync to yubikey dongle\n");
     fprintf(stdout, "   -V          Show version and exit\n");
@@ -297,7 +303,7 @@
 	return 0;
 }
 
-static char *valid_options = "?adcf:k:o:p:u:F:P:sV";
+static char *valid_options = "?adcf:k:o:i:p:u:F:P:sV";
 
 #define LONGOPT_ARG_NONE 0
 #define LONGOPT_ARG_REQUIRED 1
@@ -383,6 +389,11 @@
 				otp = strdup(optarg);
 				break;
 
+			case 'i': /* PIN code */
+				entry.flags |= YKDB_TOKEN_PIN;
+				pin = strdup(optarg);
+				break;
+
 			case 'p': /* Private UID */
 				private_uid_text = strdup(optarg);
 				break;
@@ -541,6 +552,20 @@
 		for(i=0; i<public_uid_bin_size; i++)
 			safeSnprintfAppend(ticket_enc_key, 256, "%02x", public_uid_bin[i]);
 	}
+
+	/* If a PIN code is provided, encrypt it and append it to the ticket */
+	if ( entry.flags & YKDB_TOKEN_PIN )
+	{
+		if (strlen(pin) != YKDB_PIN_SIZE) 
+		{
+			printf("Your PIN code must be exactly four characters long!\n");
+			return 1;
+		}
+		safeSnprintfAppend(ticket_enc_key, 256, "|", public_uid_bin);
+		getSHA256(pin, YKDB_PIN_SIZE, (uint8_t *)&entry.ticket.reserved);
+		for(i=0; i<YKDB_PIN_SIZE; i++)
+			safeSnprintfAppend(ticket_enc_key, 256, "%02x",pin[i]);
+	}
 	
 	if ( entry.flags & YKDB_TOKEN_ENC_PASSWORD )
 	{
@@ -631,6 +656,7 @@
 {
 	uint8_t				ticket_enc_key[256];
 	uint8_t				ticket_enc_hash[32];
+	uint8_t				pin_enc_hash[32];
 	uint8_t				i;
 
 	ykdb_entry			tmp_entry;
@@ -664,6 +690,26 @@
 		if ( memcmp(tmp_entry.password_hash, entry.password_hash, 32) )
 			return 1;
 	}
+
+/*
+	if ( tmp_entry.flags & YKDB_TOKEN_PIN )
+	{
+		if (!pin)
+		{
+			printf("Please give your PIN code!\n");
+			return 1;
+		}
+		if (strlen(pin) != 4)
+		{
+			printf("Your PIN code must be exactly four characters long!\n");
+			return 1;
+		}
+		safeSnprintfAppend(ticket_enc_key, 256, "|", public_uid_bin);
+		getSHA256(pin, 4, pin_enc_hash);
+		for(i=0; i<4; i++)
+			safeSnprintfAppend(ticket_enc_key, 256, "%02x", pin_enc_hash[i]);
+	}
+*/
 	
 	safeSnprintfAppend(ticket_enc_key, 256, "|TICKET_ENC_KEY_END");
 
--- src/utils/yk_chkpwd.c.orig	2008-09-24 09:55:24.000000000 +0200
+++ src/utils/yk_chkpwd.c	2009-04-01 15:37:29.000000000 +0200
@@ -232,15 +232,19 @@
 	}
 }
 
-int _yubi_verify_password(char *user, char *otp)
+int _yubi_verify_password(char *user, char *full_pw)
 {
 	int	i;
 
+	char	pin[MAXPASS];
+	char	otp[MAXPASS];
+
     yk_ticket           tkt;
     ykdb_entry          entry;
     ykdb_h              *handle;
     
 	uint8_t             tkt_private_uid_hash[32];
+	uint8_t             pin_enc_hash[32];
 
 	uint8_t             ticket_enc_key[256];
     uint8_t             ticket_enc_hash[32];
@@ -252,6 +256,10 @@
 	int					delta_use;
 	int					delta_session;
 
+	/* Split received password: PIN code are the first four characters */
+	strncpy(pin, full_pw, YKDB_PIN_SIZE); pin[YKDB_PIN_SIZE] = '\0';
+	strcpy(otp, full_pw + YKDB_PIN_SIZE);
+
 	D (("Recived OTP: %s", otp!=NULL?otp:""));
 
     /* set additional default values for the entry after parsing */
@@ -306,6 +314,15 @@
 	    for(i=0; i<public_uid_bin_size; i++)
 	        safeSnprintfAppend((char *)ticket_enc_key, 256, "%02x", public_uid_bin[i]);
 	}
+
+	/* add hex string format of PIN code if present */
+	if ( entry.flags & YKDB_TOKEN_PIN )
+	{
+		safeSnprintfAppend(ticket_enc_key, 256, "|", public_uid_bin);
+		getSHA256(pin, YKDB_PIN_SIZE, pin_enc_hash);
+		for(i=0; i<YKDB_PIN_SIZE; i++)
+			safeSnprintfAppend(ticket_enc_key, 256, "%02x",pin_enc_hash[i]);
+	}
 	 
 	/* close off decryption key text and generate encryption hash */
 	safeSnprintfAppend((char *)ticket_enc_key, 256, "|TICKET_ENC_KEY_END");
@@ -336,9 +353,10 @@
 
     /* hash decrypted private uid */
     getSHA256(tkt.private_uid, PRIVATE_UID_BYTE_SIZE, (uint8_t *)&tkt_private_uid_hash);
- 
+
     /* match private uid hashes */
-    if ( memcmp(&tkt_private_uid_hash, &entry.ticket.private_uid_hash, 32) )
+    if ( memcmp(&tkt_private_uid_hash, &entry.ticket.private_uid_hash, 32) || 
+	 memcmp(&pin_enc_hash, &entry.ticket.reserved, YKDB_PIN_SIZE) )
     {
         ykdbDatabaseClose(handle);
 		D (("private uid mismatch"));
