~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to libraries/libldap/tls_m.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2009-09-07 13:41:10 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20090907134110-rsnlhy8b0r21p9bg
Tags: 2.4.18-0ubuntu1
* New upstream release: (LP: #419515):
  + pcache overlay supports disconnected mode.
* Fix nss overlay load (LP: #417163).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* tls_m.c - Handle tls/ssl using Mozilla NSS. */
2
 
/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_m.c,v 1.3.2.4 2009/07/06 19:31:48 quanah Exp $ */
 
2
/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_m.c,v 1.3.2.7 2009/08/30 22:55:46 quanah Exp $ */
3
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
4
 *
5
5
 * Copyright 2008-2009 The OpenLDAP Foundation.
53
53
#include <termios.h> /* for echo on/off */
54
54
#endif
55
55
 
56
 
#include <nspr.h>
57
 
#include <private/pprio.h>
58
 
#include <nss.h>
59
 
#include <ssl.h>
60
 
#include <sslproto.h>
61
 
#include <pk11pub.h>
62
 
#include <secerr.h>
63
 
#include <keyhi.h>
 
56
#include <nspr/nspr.h>
 
57
#include <nspr/private/pprio.h>
 
58
#include <nss/nss.h>
 
59
#include <nss/ssl.h>
 
60
#include <nss/sslerr.h>
 
61
#include <nss/sslproto.h>
 
62
#include <nss/pk11pub.h>
 
63
#include <nss/secerr.h>
 
64
#include <nss/keyhi.h>
 
65
#include <nss/secmod.h>
64
66
 
65
67
typedef struct tlsm_ctx {
66
68
        PRFileDesc *tc_model;
73
75
        int tc_is_server;
74
76
        int tc_require_cert;
75
77
        PRCallOnceType tc_callonce;
 
78
        PRBool tc_using_pem;
 
79
        char *tc_slotname; /* if using pem */
76
80
#ifdef LDAP_R_COMPILE
77
81
        ldap_pvt_thread_mutex_t tc_refmutex;
78
82
#endif
86
90
 
87
91
static int tlsm_did_init;
88
92
 
 
93
static const char* pem_library = "nsspem";
 
94
static SECMODModule* pemMod = NULL;
 
95
 
89
96
#define DEFAULT_TOKEN_NAME "default"
 
97
/* sprintf format used to create token name */
 
98
#define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
 
99
 
 
100
static int tlsm_slot_count;
 
101
 
 
102
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
 
103
                (x)->pValue=(v); (x)->ulValueLen = (l);
90
104
 
91
105
/* forward declaration */
92
106
static int tlsm_init( void );
639
653
                        success = SECFailure;
640
654
                }
641
655
                break;
 
656
        /* we bypass NSS's hostname checks and do our own */
 
657
        case SSL_ERROR_BAD_CERT_DOMAIN:
 
658
                break;
642
659
        default:
643
660
                success = SECFailure;
644
661
                break;
679
696
        return "";
680
697
}
681
698
 
682
 
static SECStatus
683
 
tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
684
 
                       PRBool checksig, PRBool isServer)
685
 
{
686
 
        SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
687
 
 
688
 
        Debug( LDAP_DEBUG_TRACE,
689
 
                   "TLS certificate verification: %s: %s,",
690
 
                   ret == SECSuccess ? "ok" : "bad",
691
 
                   tlsm_dump_security_status( fd ), 0 );
692
 
 
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 ) ;
698
 
        }
699
 
 
700
 
        return ret;
701
 
}
702
 
 
703
 
static char *
704
 
tlsm_dirname(const char *pathname)
705
 
{
706
 
        char *ret = NULL;
707
 
        char *p = NULL;
708
 
        char sep = PR_GetDirectorySeparator();
709
 
 
710
 
        if (pathname && (p = PL_strrchr(pathname, sep)) && (p > pathname)) {
711
 
                ret = PL_strndup(pathname, (p - pathname));
712
 
        }
713
 
 
714
 
        return ret;
715
 
}
716
 
 
717
 
/*
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()
724
 
 */
725
 
static int
726
 
tlsm_deferred_init( void *arg )
727
 
{
728
 
        tlsm_ctx *ctx = (tlsm_ctx *)arg;
729
 
        struct ldaptls *lt = ctx->tc_config;
730
 
        char *securitydir = NULL;
731
 
        int needfree = 0;
732
 
        char *val;
733
 
        PRErrorCode errcode;
734
 
 
735
 
        /* NSS support for multi-init is coming */
736
 
#ifndef NSS_MULTI_INIT
737
 
        if ( !NSS_IsInitialized() ) {
738
 
#endif /* NSS_MULTI_INIT */
739
 
                /*
740
 
                  MOZNSS_DIR will override everything else - you can
741
 
                  always set MOZNSS_DIR to force the use of this
742
 
                  directory
743
 
                  DEFAULT_MOZNSS_DIR will only be used if the code cannot
744
 
                  find a security dir to use based on the current
745
 
                  settings
746
 
                */
747
 
                if ( (val = PR_GetEnv( "MOZNSS_DIR" ) ) && (*val) ) {
748
 
                        securitydir = PL_strdup( val );
749
 
                        needfree = 1;
750
 
                } else if ( lt->lt_cacertdir ) {
751
 
                        securitydir = lt->lt_cacertdir;
752
 
                } else if ( lt->lt_cacertfile ) {
753
 
                        securitydir = tlsm_dirname( lt->lt_cacertfile );
754
 
                        needfree = 1;
755
 
                } else if ( lt->lt_certfile ) {
756
 
                        securitydir = tlsm_dirname( lt->lt_certfile );
757
 
                        needfree = 1;
758
 
                } else if ( lt->lt_keyfile ) {
759
 
                        securitydir = tlsm_dirname( lt->lt_keyfile );
760
 
                        needfree = 1;
761
 
                } else if ( (val = PR_GetEnv( "DEFAULT_MOZNSS_DIR" ) ) && (*val) ) {
762
 
                        securitydir = PL_strdup( val );
763
 
                        needfree = 1;
764
 
                } else {
765
 
                        securitydir = "/etc/pki/nssdb";
766
 
                }
767
 
 
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 ) );
773
 
                        if ( needfree ) {
774
 
                                PL_strfree( securitydir );
775
 
                        }
776
 
                        return -1;
777
 
                }
778
 
 
779
 
                if ( needfree ) {
780
 
                        PL_strfree( securitydir );
781
 
                }
782
 
 
783
 
                NSS_SetDomesticPolicy();
784
 
                tlsm_did_init = 1; /* we did the init - we should also clean up */
785
 
#ifndef NSS_MULTI_INIT
786
 
        }
787
 
#endif /* NSS_MULTI_INIT */
788
 
 
789
 
        return 0;
790
 
}
791
 
 
792
699
#ifdef READ_PASSWORD_FROM_FILE
793
700
static char *
794
701
tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
968
875
        return tlsm_get_pin( slot, retry, ctx );
969
876
}
970
877
 
 
878
static SECStatus
 
879
tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
 
880
                       PRBool checksig, PRBool isServer)
 
881
{
 
882
        SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
 
883
 
 
884
        tlsm_dump_security_status( fd );
 
885
        Debug( LDAP_DEBUG_TRACE,
 
886
                   "TLS certificate verification: %s\n",
 
887
                   ret == SECSuccess ? "ok" : "bad", 0, 0 );
 
888
 
 
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 ) ;
 
894
        }
 
895
 
 
896
        return ret;
 
897
}
 
898
 
 
899
static int
 
900
tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
 
901
{
 
902
        int rc = -1;
 
903
 
 
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 ) );
 
911
        } else {
 
912
                rc = 0; /* success */
 
913
        }
 
914
 
 
915
        return rc;
 
916
}
 
917
 
 
918
static int
 
919
tlsm_init_tokens( tlsm_ctx *ctx )
 
920
{
 
921
        PK11SlotList *slotList;
 
922
        PK11SlotListElement *listEntry;
 
923
        int rc = 0;
 
924
 
 
925
        slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL );
 
926
 
 
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 );
 
931
                PK11_FreeSlot(slot);
 
932
        }
 
933
 
 
934
        return rc;
 
935
}
 
936
 
 
937
static int
 
938
tlsm_init_pem_module( void )
 
939
{
 
940
        int rc = 0;
 
941
        char *fullname = NULL;
 
942
        char *configstring = NULL;
 
943
 
 
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 );
 
949
 
 
950
        pemMod = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
 
951
        PR_smprintf_free( configstring );
 
952
 
 
953
        if ( !pemMod || !pemMod->loaded ) {
 
954
                if ( pemMod ) {
 
955
                        SECMOD_DestroyModule( pemMod );
 
956
                        pemMod = NULL;
 
957
                }
 
958
                rc = -1;
 
959
        }
 
960
 
 
961
        return rc;
 
962
}
 
963
 
 
964
static int
 
965
tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
 
966
{
 
967
        CK_SLOT_ID slotID;
 
968
        PK11SlotInfo *slot = NULL;
 
969
        PK11GenericObject *rv;
 
970
        CK_ATTRIBUTE *attrs;
 
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();
 
979
 
 
980
        attrs = theTemplate;
 
981
 
 
982
        if ( isca ) {
 
983
                slotID = 0; /* CA and trust objects use slot 0 */
 
984
                PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
 
985
                slotname = tmpslotname;
 
986
        } else {
 
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 );
 
990
                }
 
991
                slotname = ctx->tc_slotname;
 
992
 
 
993
                if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
 
994
                        PL_strfree( ctx->tc_certname );
 
995
                        ++ptr;
 
996
                        ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
 
997
                }
 
998
        }
 
999
 
 
1000
        slot = PK11_FindSlotByName( slotname );
 
1001
 
 
1002
        if ( !slot ) {
 
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 ) );
 
1008
                return -1;
 
1009
        }
 
1010
 
 
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++;
 
1014
        if ( isca ) {
 
1015
                PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
 
1016
        } else {
 
1017
                PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
 
1018
        }
 
1019
        /* This loads the certificate in our PEM module into the appropriate
 
1020
         * slot.
 
1021
         */
 
1022
        rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
 
1023
 
 
1024
        PK11_FreeSlot( slot );
 
1025
 
 
1026
        if ( !rv ) {
 
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 ) );
 
1032
                return -1;
 
1033
        }
 
1034
 
 
1035
        return 0;
 
1036
}
 
1037
 
 
1038
static int
 
1039
tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
 
1040
{
 
1041
        CK_SLOT_ID slotID;
 
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;
 
1048
        int retcode = 0;
 
1049
 
 
1050
        attrs = theTemplate;
 
1051
 
 
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 );
 
1055
        }
 
1056
        slot = PK11_FindSlotByName( ctx->tc_slotname );
 
1057
 
 
1058
        if ( !slot ) {
 
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 ) );
 
1064
                return -1;
 
1065
        }
 
1066
 
 
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 */ );
 
1071
 
 
1072
        if ( !rv ) {
 
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 ) );
 
1078
                retcode = -1;
 
1079
        } else {
 
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 );
 
1084
                retcode = 0;
 
1085
        }
 
1086
 
 
1087
        PK11_FreeSlot( slot );
 
1088
 
 
1089
        return retcode;
 
1090
}
 
1091
 
 
1092
static int
 
1093
tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
 
1094
{
 
1095
        PRBool isca = PR_TRUE;
 
1096
 
 
1097
        if ( cacertfile ) {
 
1098
                int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
 
1099
                if ( rc ) {
 
1100
                        return rc;
 
1101
                }
 
1102
        }
 
1103
 
 
1104
        if ( cacertdir ) {
 
1105
                PRFileInfo fi;
 
1106
                PRStatus status;
 
1107
                PRDir *dir;
 
1108
                PRDirEntry *entry;
 
1109
 
 
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",
 
1116
                                   cacertdir, errcode,
 
1117
                                   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
 
1118
                        return -1;
 
1119
                }
 
1120
 
 
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",
 
1124
                                   cacertdir, 0 ,0 );
 
1125
                        return -1;
 
1126
                }
 
1127
 
 
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",
 
1133
                                   cacertdir, errcode,
 
1134
                                   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
 
1135
                        return -1;
 
1136
                }
 
1137
 
 
1138
                status = -1;
 
1139
                do {
 
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 */
 
1145
                                }
 
1146
                                PR_smprintf_free( fullpath );
 
1147
                        }
 
1148
                } while ( NULL != entry );
 
1149
                PR_CloseDir( dir );
 
1150
 
 
1151
                if ( status ) {
 
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",
 
1155
                                   cacertdir, errcode,
 
1156
                                   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
 
1157
                        return -1;
 
1158
                }
 
1159
        }
 
1160
 
 
1161
        return 0;
 
1162
}
 
1163
 
 
1164
/*
 
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()
 
1171
 */
 
1172
static int
 
1173
tlsm_deferred_init( void *arg )
 
1174
{
 
1175
        tlsm_ctx *ctx = (tlsm_ctx *)arg;
 
1176
        struct ldaptls *lt = ctx->tc_config;
 
1177
        const char *securitydirs[3];
 
1178
        int ii;
 
1179
        int nn;
 
1180
        PRErrorCode errcode = 1;
 
1181
 
 
1182
        /* NSS support for multi-init is coming */
 
1183
#ifndef NSS_MULTI_INIT
 
1184
        if ( !NSS_IsInitialized() ) {
 
1185
#endif /* NSS_MULTI_INIT */
 
1186
                /*
 
1187
                  MOZNSS_DIR will override everything else - you can
 
1188
                  always set MOZNSS_DIR to force the use of this
 
1189
                  directory
 
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
 
1194
                  settings
 
1195
                */
 
1196
                nn = 0;
 
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 ) {
 
1203
                                continue;
 
1204
                        }
 
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 ) );
 
1210
                        } else {
 
1211
                                /* success */
 
1212
                                Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s.\n",
 
1213
                                           securitydir, 0, 0 );
 
1214
                                errcode = 0;
 
1215
                                break;
 
1216
                        }
 
1217
                }
 
1218
 
 
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 );
 
1225
                                return -1;
 
1226
                        }
 
1227
 
 
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 );
 
1234
                                return -1;
 
1235
                        }
 
1236
 
 
1237
                        if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
 
1238
                                return -1;
 
1239
                        }
 
1240
 
 
1241
                        ctx->tc_using_pem = PR_TRUE;
 
1242
                }
 
1243
 
 
1244
                NSS_SetDomesticPolicy();
 
1245
 
 
1246
                PK11_SetPasswordFunc( tlsm_pin_prompt );
 
1247
 
 
1248
                if ( tlsm_init_tokens( ctx ) ) {
 
1249
                        return -1;
 
1250
                }
 
1251
 
 
1252
                tlsm_did_init = 1; /* we did the init - we should also clean up */
 
1253
#ifndef NSS_MULTI_INIT
 
1254
        }
 
1255
#endif /* NSS_MULTI_INIT */
 
1256
 
 
1257
        return 0;
 
1258
}
 
1259
 
971
1260
static int
972
1261
tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
973
1262
{
980
1269
                return 0;
981
1270
        }
982
1271
 
983
 
        PK11_SetPasswordFunc( tlsm_pin_prompt );
984
 
 
985
1272
        if ( ( colon = PL_strchr( certname, ':' ) ) ) {
986
1273
                token_name = PL_strndup( certname, colon-certname );
987
1274
        }
1001
1288
                goto done;
1002
1289
        }
1003
1290
 
1004
 
        if ( pininfo ) {
1005
 
                PL_strfree( ctx->tc_pin_file );
1006
 
                ctx->tc_pin_file = PL_strdup( pininfo );
1007
 
        }
1008
 
 
1009
 
        if ( PK11_NeedLogin( slot ) &&
1010
 
                 ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) ) {
1011
 
                PRErrorCode errcode = PR_GetError();
1012
 
                Debug( LDAP_DEBUG_ANY,
1013
 
                           "TLS: could not authenticate to the security token %s - error %d:%s.\n",
1014
 
                           token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
1015
 
                           PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
1016
 
                goto done;
1017
 
        } else {
1018
 
                rc = 0; /* success */
1019
 
        }
 
1291
        rc = tlsm_authenticate_to_slot( ctx, slot );
1020
1292
 
1021
1293
done:
1022
1294
        PL_strfree( token_name );
1064
1336
                isServer = !isServer; /* verify the peer's cert instead */
1065
1337
        }
1066
1338
 
1067
 
        key = PK11_FindKeyByAnyCert( cert, pin_arg );
 
1339
        if ( ctx->tc_slotname ) {
 
1340
                PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
 
1341
                key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
 
1342
                PK11_FreeSlot( slot );
 
1343
        } else {
 
1344
                key = PK11_FindKeyByAnyCert( cert, pin_arg );
 
1345
        }
 
1346
 
1068
1347
        if (key) {
1069
1348
                SECCertificateUsage certUsage;
1070
1349
                PRBool checkSig = PR_TRUE;
1170
1449
static void
1171
1450
tlsm_destroy( void )
1172
1451
{
 
1452
        if (pemMod) {
 
1453
                SECMOD_DestroyModule(pemMod);
 
1454
                pemMod = NULL;
 
1455
        }
 
1456
 
1173
1457
        /* Only if we did the actual initialization */
1174
1458
        if ( tlsm_did_init ) {
1175
1459
                tlsm_did_init = 0;
1200
1484
                ctx->tc_model = NULL;
1201
1485
                memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
1202
1486
                ctx->tc_require_cert = lo->ldo_tls_require_cert;
1203
 
        } else {
1204
 
                LDAP_FREE( ctx );
1205
 
                ctx = NULL;
 
1487
                ctx->tc_verify_cert = PR_FALSE;
 
1488
                ctx->tc_using_pem = PR_FALSE;
 
1489
                ctx->tc_slotname = NULL;
1206
1490
        }
1207
1491
        return (tls_ctx *)ctx;
1208
1492
}
1237
1521
#endif
1238
1522
        if ( refcount )
1239
1523
                return;
1240
 
        PR_Close( c->tc_model );
 
1524
        if ( c->tc_model )
 
1525
                PR_Close( c->tc_model );
1241
1526
        c->tc_certdb = NULL; /* if not the default, may have to clean up */
1242
1527
        PL_strfree( c->tc_certname );
1243
1528
        c->tc_certname = NULL;
1244
1529
        PL_strfree( c->tc_pin_file );
1245
1530
        c->tc_pin_file = NULL;
 
1531
        PL_strfree( c->tc_slotname );
1246
1532
#ifdef LDAP_R_COMPILE
1247
1533
        ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
1248
1534
#endif
1366
1652
                     ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
1367
1653
                        require_cert = SSL_REQUIRE_ALWAYS;
1368
1654
                }
1369
 
                ctx->tc_verify_cert = PR_TRUE;
 
1655
                if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
 
1656
                        ctx->tc_verify_cert = PR_TRUE;
1370
1657
        } else {
1371
1658
                ctx->tc_verify_cert = PR_FALSE;
1372
1659
        }
1385
1672
                return -1;
1386
1673
        }
1387
1674
 
 
1675
        /* set up our cert and key, if any */
 
1676
        if ( lt->lt_certfile ) {
 
1677
                /* if using the PEM module, load the PEM file specified by lt_certfile */
 
1678
                /* otherwise, assume this is the name of a cert already in the db */
 
1679
                if ( ctx->tc_using_pem ) {
 
1680
                        /* this sets ctx->tc_certname to the correct value */
 
1681
                        int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE /* not a ca */ );
 
1682
                        if ( rc ) {
 
1683
                                return rc;
 
1684
                        }
 
1685
                } else {
 
1686
                        PL_strfree( ctx->tc_certname );
 
1687
                        ctx->tc_certname = PL_strdup( lt->lt_certfile );
 
1688
                }
 
1689
        }
 
1690
 
 
1691
        if ( lt->lt_keyfile ) {
 
1692
                /* if using the PEM module, load the PEM file specified by lt_keyfile */
 
1693
                /* otherwise, assume this is the pininfo for the key */
 
1694
                if ( ctx->tc_using_pem ) {
 
1695
                        /* this sets ctx->tc_certname to the correct value */
 
1696
                        int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
 
1697
                        if ( rc ) {
 
1698
                                return rc;
 
1699
                        }
 
1700
                } else {
 
1701
                        PL_strfree( ctx->tc_pin_file );
 
1702
                        ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
 
1703
                }
 
1704
        }
 
1705
 
1388
1706
        /* Set up callbacks for use by clients */
1389
1707
        if ( !ctx->tc_is_server ) {
1390
1708
                if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
1403
1721
                        return -1;
1404
1722
                }
1405
1723
 
1406
 
                /* we don't currently support import of cert/key pair - assume the certfile
1407
 
                   is really the name of a cert/key in the database in the form of
1408
 
                   tokenname:certname - also assume since this is specified, the caller
1409
 
                   wants to attempt client cert auth */
1410
 
                if ( lt->lt_certfile ) {
1411
 
                        if ( tlsm_authenticate( ctx, lt->lt_certfile, lt->lt_keyfile ) ) {
 
1724
                /* 
 
1725
                   since a cert has been specified, assume the client wants to do cert auth
 
1726
                */
 
1727
                if ( ctx->tc_certname ) {
 
1728
                        if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
1412
1729
                                Debug( LDAP_DEBUG_ANY, 
1413
1730
                                       "TLS: error: unable to authenticate to the security device for certificate %s\n",
1414
 
                                       lt->lt_certfile, 0, 0 );
 
1731
                                       ctx->tc_certname, 0, 0 );
1415
1732
                                return -1;
1416
1733
                        }
1417
 
                        if ( tlsm_clientauth_init( ctx, lt->lt_certfile ) ) {
 
1734
                        if ( tlsm_clientauth_init( ctx, ctx->tc_certname ) ) {
1418
1735
                                Debug( LDAP_DEBUG_ANY, 
1419
1736
                                       "TLS: error: unable to set up client certificate authentication using %s\n",
1420
 
                                       lt->lt_certfile, 0, 0 );
 
1737
                                       ctx->tc_certname, 0, 0 );
1421
1738
                                return -1;
1422
1739
                        }
1423
1740
                }
1428
1745
                SECStatus status;
1429
1746
 
1430
1747
                /* must have a certificate for the server to use */
1431
 
                if ( !lt->lt_certfile ) {
 
1748
                if ( !ctx->tc_certname ) {
1432
1749
                        Debug( LDAP_DEBUG_ANY, 
1433
1750
                               "TLS: error: no server certificate: must specify a certificate for the server to use\n",
1434
1751
                               0, 0, 0 );
1437
1754
 
1438
1755
                /* authenticate to the server's token - this will do nothing
1439
1756
                   if the key/cert db is not password protected */
1440
 
                if ( tlsm_authenticate( ctx, lt->lt_certfile, lt->lt_keyfile ) ) {
 
1757
                if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
1441
1758
                        Debug( LDAP_DEBUG_ANY, 
1442
1759
                               "TLS: error: unable to authenticate to the security device for certificate %s\n",
1443
 
                               lt->lt_certfile, 0, 0 );
 
1760
                               ctx->tc_certname, 0, 0 );
1444
1761
                        return -1;
1445
1762
                }
1446
1763
 
1447
1764
                /* get the server's key and cert */
1448
 
                if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, lt->lt_certfile, ctx->tc_is_server,
 
1765
                if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
1449
1766
                                                    &serverCert, &serverKey ) ) {
1450
1767
                        Debug( LDAP_DEBUG_ANY, 
1451
1768
                               "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
1452
 
                               lt->lt_certfile, 0, 0 );
 
1769
                               ctx->tc_certname, 0, 0 );
1453
1770
                        return -1;
1454
1771
                }
1455
1772
 
1464
1781
                        PRErrorCode err = PR_GetError();
1465
1782
                        Debug( LDAP_DEBUG_ANY, 
1466
1783
                               "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
1467
 
                               lt->lt_certfile, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
 
1784
                               ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
1468
1785
                        return -1;
1469
1786
                }
1470
1787
        }
1663
1980
        int rc;
1664
1981
        PRErrorCode err;
1665
1982
 
1666
 
        /* By default, NSS checks the cert hostname for us */
1667
1983
        rc = SSL_ResetHandshake( s, PR_FALSE /* server */ );
1668
1984
        if (rc) {
1669
1985
                err = PR_GetError();
1673
1989
                           err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
1674
1990
        }
1675
1991
 
1676
 
        rc = SSL_SetURL( s, ld->ld_options.ldo_defludp->lud_host );
1677
 
        if (rc) {
1678
 
                err = PR_GetError();
1679
 
                Debug( LDAP_DEBUG_TRACE, 
1680
 
                           "TLS: error: connect - seturl failure %d - error %d:%s\n",
1681
 
                           rc, err,
1682
 
                           err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
1683
 
        }
1684
 
 
1685
1992
        rc = SSL_ForceHandshake( s );
1686
1993
        if (rc) {
1687
1994
                err = PR_GetError();
1754
2061
        return 0;
1755
2062
}
1756
2063
 
 
2064
/* what kind of hostname were we given? */
 
2065
#define IS_DNS  0
 
2066
#define IS_IP4  1
 
2067
#define IS_IP6  2
 
2068
 
1757
2069
static int
1758
2070
tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
1759
2071
{
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;
 
2078
#else
 
2079
        struct in_addr addr;
 
2080
#endif
 
2081
        SECItem altname;
 
2082
        SECStatus rv;
 
2083
 
 
2084
        if( ldap_int_hostname &&
 
2085
                ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
 
2086
        {
 
2087
                name = ldap_int_hostname;
 
2088
        } else {
 
2089
                name = name_in;
 
2090
        }
 
2091
        nlen = strlen( name );
 
2092
 
 
2093
        cert = SSL_PeerCertificate( s );
 
2094
        if (!cert) {
 
2095
                Debug( LDAP_DEBUG_ANY,
 
2096
                        "TLS: unable to get peer certificate.\n",
 
2097
                        0, 0, 0 );
 
2098
                /* if this was a fatal condition, things would have
 
2099
                 * aborted long before now.
 
2100
                 */
 
2101
                return LDAP_SUCCESS;
 
2102
        }
 
2103
 
 
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))
 
2109
                        ntype = IS_IP6;
 
2110
                LDAP_FREE(n2);
 
2111
        } else 
 
2112
#endif
 
2113
        if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
 
2114
                if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
 
2115
        }
 
2116
        if (ntype == IS_DNS ) {
 
2117
                domain = strchr( name, '.' );
 
2118
                if ( domain )
 
2119
                        dlen = nlen - ( domain - name );
 
2120
        }
 
2121
 
 
2122
        ret = LDAP_LOCAL_ERROR;
 
2123
 
 
2124
        rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
 
2125
                &altname );
 
2126
        if ( rv == SECSuccess && altname.data ) {
 
2127
                PRArenaPool *arena;
 
2128
                CERTGeneralName *names, *cur;
 
2129
 
 
2130
                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
2131
                if ( !arena ) {
 
2132
                        ret = LDAP_NO_MEMORY;
 
2133
                        goto fail;
 
2134
                }
 
2135
 
 
2136
                names = cur = CERT_DecodeAltNameExtension(arena, &altname);
 
2137
                if ( !cur )
 
2138
                        goto altfail;
 
2139
 
 
2140
                do {
 
2141
                        char *host;
 
2142
                        int hlen;
 
2143
 
 
2144
                        /* ignore empty */
 
2145
                        if ( !cur->name.other.len ) continue;
 
2146
 
 
2147
                        host = cur->name.other.data;
 
2148
                        hlen = cur->name.other.len;
 
2149
 
 
2150
                        if ( cur->type == certDNSName ) {
 
2151
                                if ( ntype != IS_DNS )  continue;
 
2152
 
 
2153
                                /* is this an exact match? */
 
2154
                                if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
 
2155
                                        ret = LDAP_SUCCESS;
 
2156
                                        break;
 
2157
                                }
 
2158
 
 
2159
                                /* is this a wildcard match? */
 
2160
                                if ( domain && host[0] == '*' && host[1] == '.' &&
 
2161
                                        dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
 
2162
                                        ret = LDAP_SUCCESS;
 
2163
                                        break;
 
2164
                                }
 
2165
                        } else if ( cur->type == certIPAddress ) {
 
2166
                                if ( ntype == IS_DNS )  continue;
 
2167
                                
 
2168
#ifdef LDAP_PF_INET6
 
2169
                                if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
 
2170
                                        continue;
 
2171
                                } else
 
2172
#endif
 
2173
                                if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
 
2174
                                        continue;
 
2175
                                }
 
2176
                                if (!memcmp(host, &addr, hlen)) {
 
2177
                                        ret = LDAP_SUCCESS;
 
2178
                                        break;
 
2179
                                }
 
2180
                        }
 
2181
                } while (( cur = CERT_GetNextGeneralName( cur )) != names );
 
2182
altfail:
 
2183
                PORT_FreeArena( arena, PR_FALSE );
 
2184
                SECITEM_FreeItem( &altname, PR_FALSE );
 
2185
        }
 
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;
 
2191
                char buf[2048];
 
2192
 
 
2193
                buf[0] = '\0';
 
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 )
 
2199
                                        lastava = ava;
 
2200
                        }
 
2201
                }
 
2202
                if ( lastava ) {
 
2203
                        SECItem *av = CERT_DecodeAVAValue( &lastava->value );
 
2204
                        if ( av ) {
 
2205
                                if ( av->len == nlen && !strncasecmp( name, av->data, nlen )) {
 
2206
                                        ret = LDAP_SUCCESS;
 
2207
                                } else if ( av->data[0] == '*' && av->data[1] == '.' &&
 
2208
                                        domain && dlen == av->len - 1 && !strncasecmp( name,
 
2209
                                                av->data+1, dlen )) {
 
2210
                                        ret = LDAP_SUCCESS;
 
2211
                                } else {
 
2212
                                        int len = av->len;
 
2213
                                        if ( len >= sizeof(buf) )
 
2214
                                                len = sizeof(buf)-1;
 
2215
                                        memcpy( buf, av->data, len );
 
2216
                                        buf[len] = '\0';
 
2217
                                }
 
2218
                                SECITEM_FreeItem( av, PR_TRUE );
 
2219
                        }
 
2220
                }
 
2221
                if ( ret != LDAP_SUCCESS ) {
 
2222
                        Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
 
2223
                                "common name in certificate (%s).\n", 
 
2224
                                name, buf, 0 );
 
2225
                        ret = LDAP_CONNECT_ERROR;
 
2226
                        if ( ld->ld_error ) {
 
2227
                                LDAP_FREE( ld->ld_error );
 
2228
                        }
 
2229
                        ld->ld_error = LDAP_STRDUP(
 
2230
                                _("TLS: hostname does not match CN in peer certificate"));
 
2231
                }
 
2232
        }
 
2233
 
 
2234
fail:
 
2235
        CERT_DestroyCertificate( cert );
 
2236
        return ret;
1762
2237
}
1763
2238
 
1764
2239
static int
2005
2480
 
2006
2481
/*
2007
2482
 * Initialize TLS subsystem. Should be called only once.
 
2483
 * See tlsm_deferred_init for the bulk of the init process
2008
2484
 */
2009
2485
static int
2010
2486
tlsm_init( void )
2013
2489
 
2014
2490
        tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
2015
2491
 
2016
 
        /* see deferred init */
2017
2492
        return 0;
2018
2493
}
2019
2494
 
2190
2665
};
2191
2666
 
2192
2667
#endif /* HAVE_MOZNSS */
 
2668
/*
 
2669
  emacs settings
 
2670
  Local Variables:
 
2671
  indent-tabs-mode: t
 
2672
  tab-width: 4
 
2673
  End:
 
2674
*/