Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37402355
en ru br
Репозитории ALT
S:0.6.12.1-alt1
5.1: 0.6.1-alt5
www.altlinux.org/Changes

Группа :: Система/Основа
Пакет: pam_pkcs11

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: pam_pkcs11-0.6.9-oid-mapper.patch
Скачать


 doc/pam_pkcs11.xml           |  11 +-
 src/common/cert_info.c       | 275 +++++++++++++++++++++----------------------
 src/common/cert_info.h       |   2 +
 src/mappers/generic_mapper.c | 100 +++++++++++++++-
 4 files changed, 237 insertions(+), 151 deletions(-)
diff --git a/doc/pam_pkcs11.xml b/doc/pam_pkcs11.xml
index a073c90..27e5ef2 100644
--- a/doc/pam_pkcs11.xml
+++ b/doc/pam_pkcs11.xml
@@ -2158,8 +2158,17 @@ generic_mapper configuration file shows like:
         # module = /usr/lib/pam_pkcs11/generic_mapper.so;
 	# ignore letter case on match/compare
         ignorecase = false;
-	# Use one of "cn" , "subject" , "kpn" , "email" , "upn" , "uid" or "serial"
+	# Use one of "cn" , "subject" , "kpn" , "email" , "upn" , "uid",
+    # "serial" or any OID value, e.g. 1.2.643.100.3 .
 	cert_item  = cn;
+    # Use scramble flag to hash the extracted value with SHA1 hash
+    scramble = true;
+    # Limit the size of the hashed value to maxlen characters
+    maxlen = 15;
+    # May declare prefix and postfix that are automatically added
+    # to the extracted login values.
+    prefix = auto-;
+    postfix = -user;
 	# Declare mapfile if needed, else select "none"
 	mapfile = file:///etc/pam_pkcs11/generic_mapfile
 	# Decide if use getpwent() to map login
diff --git a/src/common/cert_info.c b/src/common/cert_info.c
index 12965e1..35600c6 100644
--- a/src/common/cert_info.c
+++ b/src/common/cert_info.c
@@ -329,47 +329,13 @@ void add_cert(X509 *cert, X509 ***certs, int *ncerts) {
         (*ncerts)++;
 }
 
+static char **cert_info_subj_obj(X509 *x509, ASN1_OBJECT *obj);
+
 /*
 * Extract Certificate's Common Name
 */
 static char **cert_info_cn(X509 *x509) {
-	static char *results[CERT_INFO_SIZE];
-	int lastpos,position;
-        X509_NAME *name = X509_get_subject_name(x509);
-        if (!name) {
-		DBG("Certificate has no subject");
-		return NULL;
-	}
-	for (position=0;position<CERT_INFO_SIZE;position++) results[position]= NULL;
-	position=0;
-	lastpos = X509_NAME_get_index_by_NID(name,NID_commonName,-1);
-	if (lastpos == -1) {
-		DBG("Certificate has no UniqueID");
-		return NULL;
-	}
-	while( ( lastpos != -1 ) && (position<CERT_INFO_MAX_ENTRIES) ) {
-	    X509_NAME_ENTRY *entry;
-	    ASN1_STRING *str;
-	    unsigned char *txt;
-	    if ( !(entry = X509_NAME_get_entry(name,lastpos)) ) {
-                DBG1("X509_get_name_entry() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
-	    if ( !(str = X509_NAME_ENTRY_get_data(entry)) ) {
-                DBG1("X509_NAME_ENTRY_get_data() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
-            if ( ( ASN1_STRING_to_UTF8(&txt, str) ) < 0) {
-                DBG1("ASN1_STRING_to_UTF8() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
-	    DBG2("%s = [%s]", OBJ_nid2sn(NID_commonName), txt);
-	    results[position++]=clone_str((const char *)txt);
-	    OPENSSL_free(txt);
-	    lastpos = X509_NAME_get_index_by_NID(name, NID_commonName, lastpos);
-	}
-	/* no more UID's availables in certificate */
-	return results;
+    return cert_info_subj_obj(x509, OBJ_nid2obj(NID_commonName));
 }
 
 /*
@@ -407,59 +373,91 @@ static char **cert_info_issuer(X509 *x509) {
 }
 
 /*
-* Extract Certificate's Kerberos Principal Name
+* Extract Certificate's value by OID (object)
 */
-static char **cert_info_kpn(X509 *x509) {
-        int i,j;
+static char **cert_info_ex_obj(X509 *x509, const ASN1_OBJECT *obj) {
+    int i, j = 0;
 	static char *entries[CERT_INFO_SIZE];
-        STACK_OF(GENERAL_NAME) *gens;
-        GENERAL_NAME *name;
-        ASN1_OBJECT *krb5PrincipalName;
-        DBG("Trying to find a Kerberos Principal Name in certificate");
-        gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
-        krb5PrincipalName = OBJ_txt2obj("1.3.6.1.5.2.2", 1);
-        if (!gens) {
-                DBG("No alternate name extensions");
-                return NULL; /* no alternate names */
-        }
-        if (!krb5PrincipalName) {
-                DBG("Cannot map KPN object");
-                return NULL;
-        }
-	for (j=0;j<CERT_INFO_SIZE;j++) entries[j] = NULL;
-        for (i=0,j=0; (i < sk_GENERAL_NAME_num(gens)) && (j<CERT_INFO_MAX_ENTRIES); i++) {
+
+    char oid[256];
+    OBJ_obj2txt(oid, sizeof(oid), obj, 0);
+
+    DBG1("Trying to find %s entry in the certificate...", oid);
+
+    STACK_OF(GENERAL_NAME) *gens;
+    GENERAL_NAME *name;
+    gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
+
+    if (gens) {
+        for (j=0; j < CERT_INFO_SIZE; j++) entries[j] = NULL;
+        for (i=0, j=0; (i < sk_GENERAL_NAME_num(gens)) && (j < CERT_INFO_MAX_ENTRIES); i++) {
             name = sk_GENERAL_NAME_value(gens, i);
-            if ( name && name->type==GEN_OTHERNAME ) {  /* test for UPN */
-                if (OBJ_cmp(name->d.otherName->type_id, krb5PrincipalName)) continue; /* object is not a UPN */
-		else {
-		    /* NOTE:
-		    from PKINIT RFC, I deduce that stored format for kerberos
-		    Principal Name is ASN1_STRING, but not sure at 100%
-		    Any help will be granted
-		    */
-		    unsigned char *txt;
-		    ASN1_TYPE *val = name->d.otherName->value;
-		    ASN1_STRING *str= val->value.asn1_string;
-                    DBG("Found Kerberos Principal Name ");
-		    if ( ( ASN1_STRING_to_UTF8(&txt, str) ) < 0) {
-                        DBG1("ASN1_STRING_to_UTF8() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                    } else {
-                        DBG1("Adding KPN entry: %s",txt);
-		        entries[j++]= clone_str((const char *)txt);
-		    }
-		}
+            if (name && name->type == GEN_OTHERNAME) {
+                if (OBJ_cmp(name->d.otherName->type_id, obj)) {
+                    continue; /* OID doesn't match */
+                } else {
+                    DBG1("Found %s entry", oid);
+                    unsigned char *txt = NULL;
+                    ASN1_TYPE *val = name->d.otherName->value;
+
+                    switch (val->type) {
+                    case V_ASN1_UTF8STRING:
+                        txt = val->value.utf8string->data;
+                        break;
+                    default:
+                        if ((ASN1_STRING_to_UTF8(&txt, val->value.asn1_string)) < 0) {
+                            DBG1("ASN1_STRING_to_UTF8() failed: %s", ERR_error_string(ERR_get_error(), NULL));
+                        }
+                        break;
+                    }
+
+                    if (txt) {
+                        DBG1("Adding entry: %s",txt);
+                        entries[j++]= clone_str((const char *)txt);
+                    }
+                }
             }
         }
+
         sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
-        ASN1_OBJECT_free(krb5PrincipalName);
-	if(j==0) {
-            DBG("Certificate does not contain a KPN entry");
+    } else {
+        DBG("No alternate name extensions");
+    }
+        
+	if (j == 0) {
+        DBG1("Certificate extensions do not contain the %s entry", oid);
 	    return NULL;
 	}
+    
 	return entries;
 }
 
 /*
+* Extract Certificate's value by OID
+*/
+static char **cert_info_oid(X509 *x509, const char *oid) {
+    ASN1_OBJECT *obj = OBJ_txt2obj(oid, 1);
+    if (!obj) {
+        DBG("Cannot map OID");
+        return NULL;
+    }
+
+    char **ret = cert_info_subj_obj(x509, obj);
+    if (!ret) {
+        ret = cert_info_ex_obj(x509, obj);
+        ASN1_OBJECT_free(obj);
+    }
+    return ret;
+}
+
+/*
+* Extract Certificate's Kerberos Principal Name
+*/
+static char **cert_info_kpn(X509 *x509) {
+    return cert_info_oid(x509, "1.3.6.1.5.2.2");
+}
+
+/*
 * Extract Certificate's email
 */
 static char **cert_info_email(X509 *x509) {
@@ -492,90 +490,73 @@ static char **cert_info_email(X509 *x509) {
 * Extract Certificate's Microsoft Universal Principal Name
 */
 static char **cert_info_upn(X509 *x509) {
-        int i,j;
-	static char *entries[CERT_INFO_SIZE];
-        STACK_OF(GENERAL_NAME) *gens;
-        GENERAL_NAME *name;
-        DBG("Trying to find an Universal Principal Name in certificate");
-        gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
-        if (!gens) {
-	    DBG("No alternate name extensions found");
-	    return NULL;
-	}
-	for (j=0;j<CERT_INFO_SIZE;j++) entries[j] = NULL;
-        for (i=0,j=0; (i < sk_GENERAL_NAME_num(gens)) && (j<CERT_INFO_MAX_ENTRIES); i++) {
-            name = sk_GENERAL_NAME_value(gens, i);
-            if ( name && name->type==GEN_OTHERNAME ) {
-                /* test for UPN */
-                if (OBJ_cmp(name->d.otherName->type_id, OBJ_nid2obj(NID_ms_upn))) continue; /* object is not a UPN */
-                DBG("Found MS Universal Principal Name ");
-                /* try to extract string and return it */
-                if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
-                    ASN1_UTF8STRING *str = name->d.otherName->value->value.utf8string;
-                    DBG1("Adding UPN NAME entry= %s",str->data);
-		    entries[j++] = clone_str((const char *)str->data);
-                } else {
-		    DBG("Found UPN entry is not an utf8string");
-		}
-            }
-        }
-        sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
-	if(j==0) {
-            DBG("Certificate does not contain a MS UPN entry");
-	    return NULL;
-	}
-	return entries;
+    return cert_info_ex_obj(x509, OBJ_nid2obj(NID_ms_upn));
 }
 
 /*
-* Extract Certificate's Unique Identifier(s)
+* Extract given field Certificate's Unique Identifier(s)
 * Array size is limited to CERT_INFO_MAX_ENTRIES UID's. expected to be enough...
 */
-static char **cert_info_uid(X509 *x509) {
+static char **cert_info_subj_obj(X509 *x509, ASN1_OBJECT *obj) {
 	static char *results[CERT_INFO_SIZE];
-	int lastpos,position;
-	int uid_type = UID_TYPE;
-        X509_NAME *name = X509_get_subject_name(x509);
-        if (!name) {
+	int lastpos = -1; int position = 0;
+    
+    char oid[256];
+    OBJ_obj2txt(oid, sizeof(oid), obj, 0);
+    
+    X509_NAME *name = X509_get_subject_name(x509);
+    if (!name) {
 		DBG("Certificate has no subject");
 		return NULL;
 	}
-	for (position=0;position<CERT_INFO_SIZE;position++) results[position]= NULL;
-	position=0;
-	lastpos = X509_NAME_get_index_by_NID(name,uid_type,-1);
-	if (lastpos == -1) {
-		uid_type = NID_userId;
-		lastpos = X509_NAME_get_index_by_NID(name,uid_type,-1);
-		if (lastpos == -1) {
-			DBG("Certificate has no UniqueID");
-			return NULL;
-		}
-	}
-	while( ( lastpos != -1 ) && (position<CERT_INFO_MAX_ENTRIES) ) {
+	for (position=0; position < CERT_INFO_SIZE; position++) {
+        results[position] = NULL;
+    }
+	position = 0;
+	lastpos = X509_NAME_get_index_by_OBJ(name, obj, -1);
+    if (lastpos == -1) {
+        DBG1("Certificate subject does not contain %s entry", oid);
+        return NULL;
+    }
+    
+	while ((lastpos != -1) && (position < CERT_INFO_MAX_ENTRIES)) {
 	    X509_NAME_ENTRY *entry;
 	    ASN1_STRING *str;
 	    unsigned char *txt;
-	    if ( !(entry = X509_NAME_get_entry(name,lastpos)) ) {
-                DBG1("X509_get_name_entry() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
+	    if ( !(entry = X509_NAME_get_entry(name, lastpos)) ) {
+            DBG1("X509_get_name_entry() failed: %s", ERR_error_string(ERR_get_error(),NULL));
+            return results;
+        }
 	    if ( !(str = X509_NAME_ENTRY_get_data(entry)) ) {
-                DBG1("X509_NAME_ENTRY_get_data() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
-            if ( ( ASN1_STRING_to_UTF8(&txt, str) ) < 0) {
-                DBG1("ASN1_STRING_to_UTF8() failed: %s", ERR_error_string(ERR_get_error(),NULL));
-                return results;
-            }
-	    DBG2("%s = [%s]", OBJ_nid2sn(UID_TYPE), txt);
-	    results[position++]=clone_str((const char *)txt);
+            DBG1("X509_NAME_ENTRY_get_data() failed: %s", ERR_error_string(ERR_get_error(),NULL));
+            return results;
+        }
+        if ( (ASN1_STRING_to_UTF8(&txt, str)) < 0) {
+            DBG1("ASN1_STRING_to_UTF8() failed: %s", ERR_error_string(ERR_get_error(),NULL));
+            return results;
+        }
+	    DBG2("%s = [%s]", oid, txt);
+	    results[position++] = clone_str((const char *)txt);
 	    OPENSSL_free(txt);
-	    lastpos = X509_NAME_get_index_by_NID(name, UID_TYPE, lastpos);
+	    lastpos = X509_NAME_get_index_by_OBJ(name, obj, lastpos);
 	}
-	/* no more UID's availables in certificate */
+	/* no more objects availables in the certificate */
+
+    if (position == 0) {
+        DBG1("Certificate subject does not contain %s entry", oid);
+        return NULL;
+    }
 	return results;
 }
 
+/*
+* Extract Certificate's Unique Identifier(s)
+* Array size is limited to CERT_INFO_MAX_ENTRIES UID's. expected to be enough...
+*/
+static char **cert_info_uid(X509 *x509) {
+    return cert_info_subj_obj(x509, OBJ_nid2obj(NID_userId));
+}
+
 /* convert publickey into PEM format */
 static char *key2pem(EVP_PKEY *key) {
 	int len;
@@ -941,6 +922,12 @@ char **cert_info(X509 *x509, int type, const char *algorithm ) {
 	    default           :
 		DBG1("Invalid info type requested: %d",type);
 		return NULL;
+        case CERT_OID:
+            if ( !algorithm ) {
+                DBG("Requires OID value in the \"algorithm\" argument");
+                return NULL;
+            }
+            return cert_info_oid(x509, algorithm);
 	}
 	/* should not get here */
 	return NULL;
diff --git a/src/common/cert_info.h b/src/common/cert_info.h
index 3b3353e..2d3c6d5 100644
--- a/src/common/cert_info.h
+++ b/src/common/cert_info.h
@@ -47,6 +47,8 @@
 #define CERT_SERIAL	12
 /** Certificate key algorithm */
 #define CERT_KEY_ALG	13
+/** Certificate value by OID */
+#define CERT_OID    100
 
 /** Max size of returned certificate content array */
 #define CERT_INFO_SIZE 16
diff --git a/src/mappers/generic_mapper.c b/src/mappers/generic_mapper.c
index 1f5a214..53baacd 100644
--- a/src/mappers/generic_mapper.c
+++ b/src/mappers/generic_mapper.c
@@ -33,6 +33,8 @@
 #include "../common/error.h"
 #include "../common/strings.h"
 #include "../common/cert_info.h"
+#include "../common/base64.h"
+#include <openssl/sha.h>
 #include "mapper.h"
 #include "generic_mapper.h"
 
@@ -44,14 +46,93 @@ static const char *mapfile = "none";
 static int usepwent = 0;
 static int ignorecase = 0;
 static int id_type = CERT_CN;
+static const char *algorithm = ALGORITHM_NULL;
 static int debug = 0;
+static const char *prefix;
+static const char *postfix;
+static int scramble = 0;
+
+#define MAX_ENTRY_LEN 256
+static int maxlen = MAX_ENTRY_LEN;
+
+static char *scramble_entry(const char* entry);
 
 static char **generic_mapper_find_entries(X509 *x509, void *context) {
-        if (!x509) {
-                DBG("NULL certificate provided");
-                return NULL;
+    if (!x509) {
+        DBG("NULL certificate provided");
+        return NULL;
+    }
+
+    char **entries = cert_info(x509, id_type, algorithm);
+    if (!entries) {
+        return NULL;
+    }
+
+    char *entry; int n;
+    char *entrybuf;
+    for (n=0, entry=entries[n]; entry; entry=entries[++n]) {
+        if (scramble) {
+            entries[n] = scramble_entry(entry);
+            // FIXME: free(entry) ?
+            entry = entries[n];
         }
-	return cert_info(x509, id_type, ALGORITHM_NULL);
+        if ((prefix || postfix) && NULL != entry)  {
+            entrybuf = malloc(MAX_ENTRY_LEN);
+            if (!entrybuf) {
+                DBG("Unable to allocate entry buffer");
+                entries[n] = NULL;
+            } else {
+                snprintf(entrybuf, MAX_ENTRY_LEN, "%s%s%s",
+                         prefix, entry, postfix);
+                entries[n] = entrybuf;
+                // FIXME: free(entry) ?
+                entry = entries[n];
+            }
+        }
+    }
+    
+	return entries;
+}
+
+#define SHA1_LENGTH 20
+
+static char *scramble_entry(const char* entry) {
+    unsigned char hash[SHA1_LENGTH];
+    size_t entrysize = (4 * ((sizeof(hash) + 2) / 3)) + 1;
+    char *entrybuf;
+    SHA1(entry, strlen(entry), hash);
+
+    entrybuf = malloc(entrysize);
+    if (!entrybuf) {
+        DBG("Unable to allocate entry buffer");
+        return NULL;
+    }
+
+    size_t outlen = entrysize;
+    if ( 0 != base64_encode(hash, sizeof(hash), entrybuf, &outlen) ) {
+        DBG("Unexpected error: unable to BASE64-encode the entry");
+        return NULL;
+    }
+    
+    int i;
+    for (i = 0; i < outlen; i++) {
+        if (entrybuf[i] >= 'A' && entrybuf[i] <= 'Z') {
+            entrybuf[i] = entrybuf[i] + 'a' - 'A';
+        } else {
+            switch (entrybuf[i]) {
+            case '+':
+            case '/':
+            case '=':
+                entrybuf[i] = 'o';
+            }
+        }
+    }
+
+    if (outlen > maxlen) {
+        entrybuf[maxlen] = '\0';
+    }
+
+    return entrybuf;
 }
 
 static char **get_mapped_entries(char **entries) {
@@ -175,7 +256,11 @@ mapper_module * generic_mapper_module_init(scconf_block *blk,const char *name) {
 	ignorecase = scconf_get_bool( blk,"ignorecase",0);
 	usepwent = scconf_get_bool( blk,"use_getpwent",0);
 	mapfile= scconf_get_str(blk,"mapfile",mapfile);
-	item= scconf_get_str(blk,"cert_item","cn");
+	item = scconf_get_str(blk,"cert_item","cn");
+    prefix = scconf_get_str(blk,"prefix", "");
+    postfix = scconf_get_str(blk,"postfix", "");
+    scramble = scconf_get_bool(blk,"scramble", 0);
+    maxlen = scconf_get_int(blk,"maxlen", MAX_ENTRY_LEN);
 	} else {
 		/* should not occurs, but... */
 		DBG1("No block declaration for mapper '%s'",name);
@@ -188,7 +273,10 @@ mapper_module * generic_mapper_module_init(scconf_block *blk,const char *name) {
 	else if (!strcasecmp(item,"upn") )    id_type=CERT_UPN;
 	else if (!strcasecmp(item,"uid") )    id_type=CERT_UID;
 	else if (!strcasecmp(item,"serial") ) id_type=CERT_SERIAL;
-	else {
+	else if (strlen(item) > 2 && item[0] >= '0' && item[0] < '3' && item[1] == '.') {
+        id_type = CERT_OID;
+        algorithm = item;
+    } else {
 	    DBG1("Invalid certificate item to search '%s'; using 'cn'",item);
 	}
 	pt = init_mapper_st(blk,name);
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin