683
tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
684
PRBool checksig, PRBool isServer)
686
SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
688
Debug( LDAP_DEBUG_TRACE,
689
"TLS certificate verification: %s: %s,",
690
ret == SECSuccess ? "ok" : "bad",
691
tlsm_dump_security_status( fd ), 0 );
693
if ( ret != SECSuccess ) {
694
PRErrorCode errcode = PORT_GetError();
695
Debug( LDAP_DEBUG_ANY,
696
"TLS certificate verification: Error, %d: %s\n",
697
errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
704
tlsm_dirname(const char *pathname)
708
char sep = PR_GetDirectorySeparator();
710
if (pathname && (p = PL_strrchr(pathname, sep)) && (p > pathname)) {
711
ret = PL_strndup(pathname, (p - pathname));
718
* This is the part of the init we defer until we get the
719
* actual security configuration information. This is
720
* only called once, protected by a PRCallOnce
721
* NOTE: This must be done before the first call to SSL_ImportFD,
722
* especially the setting of the policy
723
* NOTE: This must be called after fork()
726
tlsm_deferred_init( void *arg )
728
tlsm_ctx *ctx = (tlsm_ctx *)arg;
729
struct ldaptls *lt = ctx->tc_config;
730
char *securitydir = NULL;
735
/* NSS support for multi-init is coming */
736
#ifndef NSS_MULTI_INIT
737
if ( !NSS_IsInitialized() ) {
738
#endif /* NSS_MULTI_INIT */
740
MOZNSS_DIR will override everything else - you can
741
always set MOZNSS_DIR to force the use of this
743
DEFAULT_MOZNSS_DIR will only be used if the code cannot
744
find a security dir to use based on the current
747
if ( (val = PR_GetEnv( "MOZNSS_DIR" ) ) && (*val) ) {
748
securitydir = PL_strdup( val );
750
} else if ( lt->lt_cacertdir ) {
751
securitydir = lt->lt_cacertdir;
752
} else if ( lt->lt_cacertfile ) {
753
securitydir = tlsm_dirname( lt->lt_cacertfile );
755
} else if ( lt->lt_certfile ) {
756
securitydir = tlsm_dirname( lt->lt_certfile );
758
} else if ( lt->lt_keyfile ) {
759
securitydir = tlsm_dirname( lt->lt_keyfile );
761
} else if ( (val = PR_GetEnv( "DEFAULT_MOZNSS_DIR" ) ) && (*val) ) {
762
securitydir = PL_strdup( val );
765
securitydir = "/etc/pki/nssdb";
768
if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) {
769
errcode = PORT_GetError();
770
Debug( LDAP_DEBUG_ANY,
771
"TLS: could not initialize moznss using security dir %s - error %d:%s.\n",
772
securitydir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
774
PL_strfree( securitydir );
780
PL_strfree( securitydir );
783
NSS_SetDomesticPolicy();
784
tlsm_did_init = 1; /* we did the init - we should also clean up */
785
#ifndef NSS_MULTI_INIT
787
#endif /* NSS_MULTI_INIT */
792
699
#ifdef READ_PASSWORD_FROM_FILE
794
701
tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
968
875
return tlsm_get_pin( slot, retry, ctx );
879
tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
880
PRBool checksig, PRBool isServer)
882
SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
884
tlsm_dump_security_status( fd );
885
Debug( LDAP_DEBUG_TRACE,
886
"TLS certificate verification: %s\n",
887
ret == SECSuccess ? "ok" : "bad", 0, 0 );
889
if ( ret != SECSuccess ) {
890
PRErrorCode errcode = PORT_GetError();
891
Debug( LDAP_DEBUG_ANY,
892
"TLS certificate verification: Error, %d: %s\n",
893
errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
900
tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
904
if ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) {
905
char *token_name = PK11_GetTokenName( slot );
906
PRErrorCode errcode = PR_GetError();
907
Debug( LDAP_DEBUG_ANY,
908
"TLS: could not authenticate to the security token %s - error %d:%s.\n",
909
token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
910
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
912
rc = 0; /* success */
919
tlsm_init_tokens( tlsm_ctx *ctx )
921
PK11SlotList *slotList;
922
PK11SlotListElement *listEntry;
925
slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL );
927
for ( listEntry = PK11_GetFirstSafe( slotList ); !rc && listEntry;
928
listEntry = listEntry->next) {
929
PK11SlotInfo *slot = listEntry->slot;
930
rc = tlsm_authenticate_to_slot( ctx, slot );
938
tlsm_init_pem_module( void )
941
char *fullname = NULL;
942
char *configstring = NULL;
944
/* get the system dependent library name */
945
fullname = PR_GetLibraryName( NULL, pem_library );
946
/* Load our PKCS#11 module */
947
configstring = PR_smprintf( "library=%s name=PEM parameters=\"\"", fullname );
948
PR_smprintf_free( fullname );
950
pemMod = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
951
PR_smprintf_free( configstring );
953
if ( !pemMod || !pemMod->loaded ) {
955
SECMOD_DestroyModule( pemMod );
965
tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
968
PK11SlotInfo *slot = NULL;
969
PK11GenericObject *rv;
971
CK_ATTRIBUTE theTemplate[20];
972
CK_BBOOL cktrue = CK_TRUE;
973
CK_BBOOL ckfalse = CK_FALSE;
974
CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
975
char tmpslotname[64];
976
char *slotname = NULL;
977
const char *ptr = NULL;
978
char sep = PR_GetDirectorySeparator();
983
slotID = 0; /* CA and trust objects use slot 0 */
984
PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
985
slotname = tmpslotname;
987
if ( ctx->tc_slotname == NULL ) { /* need new slot */
988
slotID = ++tlsm_slot_count;
989
ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
991
slotname = ctx->tc_slotname;
993
if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
994
PL_strfree( ctx->tc_certname );
996
ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
1000
slot = PK11_FindSlotByName( slotname );
1003
PRErrorCode errcode = PR_GetError();
1004
Debug( LDAP_DEBUG_ANY,
1005
"TLS: could not find the slot for certificate %s - error %d:%s.\n",
1006
ctx->tc_certname, errcode,
1007
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1011
PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1012
PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1013
PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1015
PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1017
PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
1019
/* This loads the certificate in our PEM module into the appropriate
1022
rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
1024
PK11_FreeSlot( slot );
1027
PRErrorCode errcode = PR_GetError();
1028
Debug( LDAP_DEBUG_ANY,
1029
"TLS: could not add the certificate %s - error %d:%s.\n",
1030
ctx->tc_certname, errcode,
1031
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1039
tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
1042
PK11SlotInfo * slot = NULL;
1043
PK11GenericObject *rv;
1044
CK_ATTRIBUTE *attrs;
1045
CK_ATTRIBUTE theTemplate[20];
1046
CK_BBOOL cktrue = CK_TRUE;
1047
CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
1050
attrs = theTemplate;
1052
if ( ctx->tc_slotname == NULL ) { /* need new slot */
1053
slotID = ++tlsm_slot_count;
1054
ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
1056
slot = PK11_FindSlotByName( ctx->tc_slotname );
1059
PRErrorCode errcode = PR_GetError();
1060
Debug( LDAP_DEBUG_ANY,
1061
"TLS: could not find the slot %s for the private key - error %d:%s.\n",
1062
ctx->tc_slotname, errcode,
1063
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1067
PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
1068
PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
1069
PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
1070
rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
1073
PRErrorCode errcode = PR_GetError();
1074
Debug( LDAP_DEBUG_ANY,
1075
"TLS: could not add the certificate %s - error %d:%s.\n",
1076
ctx->tc_certname, errcode,
1077
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1080
/* When adding an encrypted key the PKCS#11 will be set as removed */
1081
/* This will force the token to be seen as re-inserted */
1082
SECMOD_WaitForAnyTokenEvent( pemMod, 0, 0 );
1083
PK11_IsPresent( slot );
1087
PK11_FreeSlot( slot );
1093
tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
1095
PRBool isca = PR_TRUE;
1098
int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
1110
memset( &fi, 0, sizeof(fi) );
1111
status = PR_GetFileInfo( cacertdir, &fi );
1112
if ( PR_SUCCESS != status) {
1113
PRErrorCode errcode = PR_GetError();
1114
Debug( LDAP_DEBUG_ANY,
1115
"TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
1117
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1121
if ( fi.type != PR_FILE_DIRECTORY ) {
1122
Debug( LDAP_DEBUG_ANY,
1123
"TLS: error: the CA certificate directory %s is not a directory.\n",
1128
dir = PR_OpenDir( cacertdir );
1129
if ( NULL == dir ) {
1130
PRErrorCode errcode = PR_GetError();
1131
Debug( LDAP_DEBUG_ANY,
1132
"TLS: could not open the CA certificate directory %s - error %d:%s.\n",
1134
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1140
entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
1141
if ( NULL != entry ) {
1142
char *fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
1143
if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
1144
status = 0; /* found at least 1 valid CA file in the dir */
1146
PR_smprintf_free( fullpath );
1148
} while ( NULL != entry );
1152
PRErrorCode errcode = PR_GetError();
1153
Debug( LDAP_DEBUG_ANY,
1154
"TLS: did not find any valid CA certificate files in the CA certificate directory %s - error %d:%s.\n",
1156
PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1165
* This is the part of the init we defer until we get the
1166
* actual security configuration information. This is
1167
* only called once, protected by a PRCallOnce
1168
* NOTE: This must be done before the first call to SSL_ImportFD,
1169
* especially the setting of the policy
1170
* NOTE: This must be called after fork()
1173
tlsm_deferred_init( void *arg )
1175
tlsm_ctx *ctx = (tlsm_ctx *)arg;
1176
struct ldaptls *lt = ctx->tc_config;
1177
const char *securitydirs[3];
1180
PRErrorCode errcode = 1;
1182
/* NSS support for multi-init is coming */
1183
#ifndef NSS_MULTI_INIT
1184
if ( !NSS_IsInitialized() ) {
1185
#endif /* NSS_MULTI_INIT */
1187
MOZNSS_DIR will override everything else - you can
1188
always set MOZNSS_DIR to force the use of this
1190
If using MOZNSS, specify the location of the moznss db dir
1191
in the cacertdir directive of the OpenLDAP configuration.
1192
DEFAULT_MOZNSS_DIR will only be used if the code cannot
1193
find a security dir to use based on the current
1197
securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
1198
securitydirs[nn++] = lt->lt_cacertdir;
1199
securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
1200
for (ii = 0; ii < nn; ++ii) {
1201
const char *securitydir = securitydirs[ii];
1202
if ( NULL == securitydir ) {
1205
if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) {
1206
errcode = PORT_GetError();
1207
Debug( LDAP_DEBUG_TRACE,
1208
"TLS: could not initialize moznss using security dir %s - error %d:%s.\n",
1209
securitydir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1212
Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s.\n",
1213
securitydir, 0, 0 );
1219
if ( errcode ) { /* no moznss db found, or not using moznss db */
1220
if ( NSS_NoDB_Init( NULL ) ) {
1221
errcode = PORT_GetError();
1222
Debug( LDAP_DEBUG_ANY,
1223
"TLS: could not initialize moznss - error %d:%s.\n",
1224
errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1228
/* initialize the PEM module */
1229
if ( tlsm_init_pem_module() ) {
1230
errcode = PORT_GetError();
1231
Debug( LDAP_DEBUG_ANY,
1232
"TLS: could not initialize moznss PEM module - error %d:%s.\n",
1233
errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
1237
if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
1241
ctx->tc_using_pem = PR_TRUE;
1244
NSS_SetDomesticPolicy();
1246
PK11_SetPasswordFunc( tlsm_pin_prompt );
1248
if ( tlsm_init_tokens( ctx ) ) {
1252
tlsm_did_init = 1; /* we did the init - we should also clean up */
1253
#ifndef NSS_MULTI_INIT
1255
#endif /* NSS_MULTI_INIT */
972
1261
tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
2064
/* what kind of hostname were we given? */
1758
2070
tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
1760
/* NSS already does a hostname check */
1761
return LDAP_SUCCESS;
2072
tlsm_session *s = (tlsm_session *)session;
2073
CERTCertificate *cert;
2074
const char *name, *domain = NULL, *ptr;
2075
int i, ret, ntype = IS_DNS, nlen, dlen;
2076
#ifdef LDAP_PF_INET6
2077
struct in6_addr addr;
2079
struct in_addr addr;
2084
if( ldap_int_hostname &&
2085
( !name_in || !strcasecmp( name_in, "localhost" ) ) )
2087
name = ldap_int_hostname;
2091
nlen = strlen( name );
2093
cert = SSL_PeerCertificate( s );
2095
Debug( LDAP_DEBUG_ANY,
2096
"TLS: unable to get peer certificate.\n",
2098
/* if this was a fatal condition, things would have
2099
* aborted long before now.
2101
return LDAP_SUCCESS;
2104
#ifdef LDAP_PF_INET6
2105
if (name[0] == '[' && strchr(name, ']')) {
2106
char *n2 = ldap_strdup(name+1);
2107
*strchr(n2, ']') = 0;
2108
if (inet_pton(AF_INET6, n2, &addr))
2113
if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
2114
if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
2116
if (ntype == IS_DNS ) {
2117
domain = strchr( name, '.' );
2119
dlen = nlen - ( domain - name );
2122
ret = LDAP_LOCAL_ERROR;
2124
rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
2126
if ( rv == SECSuccess && altname.data ) {
2128
CERTGeneralName *names, *cur;
2130
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2132
ret = LDAP_NO_MEMORY;
2136
names = cur = CERT_DecodeAltNameExtension(arena, &altname);
2145
if ( !cur->name.other.len ) continue;
2147
host = cur->name.other.data;
2148
hlen = cur->name.other.len;
2150
if ( cur->type == certDNSName ) {
2151
if ( ntype != IS_DNS ) continue;
2153
/* is this an exact match? */
2154
if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
2159
/* is this a wildcard match? */
2160
if ( domain && host[0] == '*' && host[1] == '.' &&
2161
dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
2165
} else if ( cur->type == certIPAddress ) {
2166
if ( ntype == IS_DNS ) continue;
2168
#ifdef LDAP_PF_INET6
2169
if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
2173
if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
2176
if (!memcmp(host, &addr, hlen)) {
2181
} while (( cur = CERT_GetNextGeneralName( cur )) != names );
2183
PORT_FreeArena( arena, PR_FALSE );
2184
SECITEM_FreeItem( &altname, PR_FALSE );
2186
/* no altnames matched, try the CN */
2187
if ( ret != LDAP_SUCCESS ) {
2188
/* find the last CN */
2189
CERTRDN *rdn, **rdns;
2190
CERTAVA *lastava = NULL;
2194
rdns = cert->subject.rdns;
2195
while ( rdns && ( rdn = *rdns++ )) {
2196
CERTAVA *ava, **avas = rdn->avas;
2197
while ( avas && ( ava = *avas++ )) {
2198
if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
2203
SECItem *av = CERT_DecodeAVAValue( &lastava->value );
2205
if ( av->len == nlen && !strncasecmp( name, av->data, nlen )) {
2207
} else if ( av->data[0] == '*' && av->data[1] == '.' &&
2208
domain && dlen == av->len - 1 && !strncasecmp( name,
2209
av->data+1, dlen )) {
2213
if ( len >= sizeof(buf) )
2214
len = sizeof(buf)-1;
2215
memcpy( buf, av->data, len );
2218
SECITEM_FreeItem( av, PR_TRUE );
2221
if ( ret != LDAP_SUCCESS ) {
2222
Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
2223
"common name in certificate (%s).\n",
2225
ret = LDAP_CONNECT_ERROR;
2226
if ( ld->ld_error ) {
2227
LDAP_FREE( ld->ld_error );
2229
ld->ld_error = LDAP_STRDUP(
2230
_("TLS: hostname does not match CN in peer certificate"));
2235
CERT_DestroyCertificate( cert );