nss-policy-check.c (9409B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* This program can be used to check the validity of a NSS crypto policy 6 * configuration file, specified using a config= line. 7 * 8 * Exit codes: 9 * failure: 2 10 * warning: 1 11 * success: 0 12 */ 13 14 #include <limits.h> 15 #include <errno.h> 16 #include <stdio.h> 17 #include "utilparst.h" 18 #include "nss.h" 19 #include "secport.h" 20 #include "secutil.h" 21 #include "secmod.h" 22 #include "ssl.h" 23 #include "prenv.h" 24 #include "plgetopt.h" 25 26 const char *sWarn = "WARN"; 27 const char *sInfo = "INFO"; 28 29 void 30 get_tls_info(SSLProtocolVariant protocolVariant, const char *display) 31 { 32 SSLVersionRange vrange_supported, vrange_enabled; 33 unsigned num_enabled = 0; 34 PRBool failed = PR_FALSE; 35 36 /* We assume SSL v2 is inactive, and therefore SSL_VersionRangeGetDefault 37 * gives complete information. */ 38 if ((SSL_VersionRangeGetSupported(protocolVariant, &vrange_supported) != SECSuccess) || 39 (SSL_VersionRangeGetDefault(protocolVariant, &vrange_enabled) != SECSuccess) || 40 !vrange_enabled.min || 41 !vrange_enabled.max || 42 vrange_enabled.max < vrange_supported.min || 43 vrange_enabled.min > vrange_supported.max) { 44 failed = PR_TRUE; 45 } else { 46 if (vrange_enabled.min < vrange_supported.min) { 47 vrange_enabled.min = vrange_supported.min; 48 } 49 if (vrange_enabled.max > vrange_supported.max) { 50 vrange_enabled.max = vrange_supported.max; 51 } 52 if (vrange_enabled.min > vrange_enabled.max) { 53 failed = PR_TRUE; 54 } 55 } 56 if (failed) { 57 num_enabled = 0; 58 } else { 59 num_enabled = vrange_enabled.max - vrange_enabled.min + 1; 60 } 61 fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s-VERSIONS: %u\n", 62 num_enabled ? sInfo : sWarn, display, num_enabled); 63 if (!num_enabled) { 64 PR_SetEnv("NSS_POLICY_WARN=1"); 65 } 66 } 67 68 #ifndef PATH_MAX 69 #define PATH_MAX 1024 70 #endif 71 72 /* private flags for policy check; should be in sync with pk11wrap/pk11pars.c */ 73 #define SECMOD_FLAG_POLICY_CHECK_IDENTIFIER 0x01 74 #define SECMOD_FLAG_POLICY_CHECK_VALUE 0x02 75 76 static void 77 printUsage(const char *progName) 78 { 79 fprintf(stderr, 80 "Usage: %s [options] <path-to-policy-file>\n" 81 "\tWhere options are:\n" 82 "\t-f flag\t Set policy check flag (can be specified multiple times)\n" 83 "\t \t Possible flags: \"identifier\" or \"value\"\n", 84 progName); 85 } 86 87 int 88 main(int argc, char **argv) 89 { 90 const PRUint16 *cipherSuites = SSL_ImplementedCiphers; 91 int i; 92 SECStatus rv; 93 SECMODModule *module = NULL; 94 char path[PATH_MAX]; 95 const char *filename; 96 char moduleSpec[1024 + PATH_MAX]; 97 unsigned num_enabled = 0; 98 int result = 0; 99 char *flags = NULL; 100 PLOptState *optstate = NULL; 101 PLOptStatus status; 102 char *fullPath = NULL; 103 int fullPathLen; 104 char *progName = NULL; 105 PRUint32 policyCheckFlags = 0; 106 107 progName = PORT_Strdup(argv[0]); 108 if (!progName) { 109 result = 2; 110 goto loser_no_shutdown; 111 } 112 113 /* Use PL_CreateOptState as SECU_ParseCommandLine ignores 114 * positional parameters */ 115 optstate = PL_CreateOptState(argc, argv, "f:"); 116 if (!optstate) { 117 result = 2; 118 goto loser_no_shutdown; 119 } 120 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 121 switch (optstate->option) { 122 case 0: /* positional parameter */ 123 fullPath = PL_strdup(optstate->value); 124 if (!fullPath) { 125 result = 2; 126 goto loser_no_shutdown; 127 } 128 goto breakout; 129 case 'f': 130 if (!PORT_Strcmp(optstate->value, "identifier")) { 131 policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_IDENTIFIER; 132 } else if (!PORT_Strcmp(optstate->value, "value")) { 133 policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_VALUE; 134 } else { 135 fprintf(stderr, "not a valid flag: %s\n", optstate->value); 136 printUsage(progName); 137 result = 2; 138 goto loser_no_shutdown; 139 } 140 break; 141 default: 142 printUsage(progName); 143 result = 2; 144 goto loser_no_shutdown; 145 } 146 } 147 breakout: 148 if (status != PL_OPT_OK || !fullPath) { 149 printUsage(progName); 150 result = 2; 151 goto loser_no_shutdown; 152 } 153 154 fullPathLen = strlen(fullPath); 155 156 if (!fullPathLen || PR_Access(fullPath, PR_ACCESS_READ_OK) != PR_SUCCESS) { 157 fprintf(stderr, "Error: cannot read file %s\n", fullPath); 158 result = 2; 159 goto loser_no_shutdown; 160 } 161 162 if (fullPathLen >= PATH_MAX) { 163 fprintf(stderr, "Error: filename parameter is too long\n"); 164 result = 2; 165 goto loser_no_shutdown; 166 } 167 168 path[0] = 0; 169 filename = fullPath + fullPathLen - 1; 170 while ((filename > fullPath) && (*filename != NSSUTIL_PATH_SEPARATOR[0])) { 171 filename--; 172 } 173 174 if (filename == fullPath) { 175 PORT_Strcpy(path, "."); 176 } else { 177 filename++; /* Go past the path separator. */ 178 PORT_Strncat(path, fullPath, (filename - fullPath)); 179 } 180 181 PR_SetEnv("NSS_IGNORE_SYSTEM_POLICY=1"); 182 rv = NSS_NoDB_Init(NULL); 183 if (rv != SECSuccess) { 184 fprintf(stderr, "NSS_Init failed: %s\n", PORT_ErrorToString(PR_GetError())); 185 result = 2; 186 goto loser_no_shutdown; 187 } 188 189 PR_SetEnv("NSS_POLICY_LOADED=0"); 190 PR_SetEnv("NSS_POLICY_FAIL=0"); 191 PR_SetEnv("NSS_POLICY_WARN=0"); 192 193 flags = PORT_Strdup("internal,moduleDB,skipFirst,moduleDBOnly,critical,printPolicyFeedback"); 194 if (!flags) { 195 result = 2; 196 goto loser_no_shutdown; 197 } 198 199 if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_IDENTIFIER) { 200 char *newflags; 201 202 newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckIdentifier") + 1); 203 if (!newflags) { 204 result = 2; 205 goto loser_no_shutdown; 206 } 207 flags = newflags; 208 PORT_Strcat(flags, ",policyCheckIdentifier"); 209 } 210 211 if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE) { 212 char *newflags; 213 214 newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckValue") + 1); 215 if (!newflags) { 216 result = 2; 217 goto loser_no_shutdown; 218 } 219 flags = newflags; 220 PORT_Strcat(flags, ",policyCheckValue"); 221 } 222 223 snprintf(moduleSpec, sizeof(moduleSpec), 224 "name=\"Policy File\" " 225 "parameters=\"configdir='sql:%s' " 226 "secmod='%s' " 227 "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" " 228 "NSS=\"flags=%s\"", 229 path, filename, flags); 230 231 module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE); 232 if (!module || !module->loaded || atoi(PR_GetEnvSecure("NSS_POLICY_LOADED")) != 1) { 233 fprintf(stderr, "Error: failed to load policy file\n"); 234 result = 2; 235 goto loser; 236 } 237 238 rv = SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); 239 if (rv != SECSuccess) { 240 fprintf(stderr, "enable SSL_SECURITY failed: %s\n", PORT_ErrorToString(PR_GetError())); 241 result = 2; 242 goto loser; 243 } 244 245 for (i = 0; i < SSL_NumImplementedCiphers; i++) { 246 PRUint16 suite = cipherSuites[i]; 247 PRBool enabled; 248 SSLCipherSuiteInfo info; 249 250 rv = SSL_CipherPrefGetDefault(suite, &enabled); 251 if (rv != SECSuccess) { 252 fprintf(stderr, 253 "SSL_CipherPrefGetDefault didn't like value 0x%04x (i = %d): %s\n", 254 suite, i, PORT_ErrorToString(PR_GetError())); 255 continue; 256 } 257 rv = SSL_GetCipherSuiteInfo(suite, &info, (int)(sizeof info)); 258 if (rv != SECSuccess) { 259 fprintf(stderr, 260 "SSL_GetCipherSuiteInfo didn't like value 0x%04x (i = %d): %s\n", 261 suite, i, PORT_ErrorToString(PR_GetError())); 262 continue; 263 } 264 if (enabled) { 265 ++num_enabled; 266 fprintf(stderr, "NSS-POLICY-INFO: ciphersuite %s is enabled\n", info.cipherSuiteName); 267 } 268 } 269 fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CIPHERSUITES: %u\n", num_enabled ? sInfo : sWarn, num_enabled); 270 if (!num_enabled) { 271 PR_SetEnv("NSS_POLICY_WARN=1"); 272 } 273 274 get_tls_info(ssl_variant_stream, "TLS"); 275 get_tls_info(ssl_variant_datagram, "DTLS"); 276 277 if (atoi(PR_GetEnvSecure("NSS_POLICY_FAIL")) != 0) { 278 result = 2; 279 } else if (atoi(PR_GetEnvSecure("NSS_POLICY_WARN")) != 0) { 280 result = 1; 281 } 282 283 loser: 284 if (module) { 285 SECMOD_DestroyModule(module); 286 } 287 rv = NSS_Shutdown(); 288 if (rv != SECSuccess) { 289 fprintf(stderr, "NSS_Shutdown failed: %s\n", PORT_ErrorToString(PR_GetError())); 290 result = 2; 291 } 292 loser_no_shutdown: 293 if (optstate) { 294 PL_DestroyOptState(optstate); 295 } 296 PORT_Free(flags); 297 PORT_Free(progName); 298 PORT_Free(fullPath); 299 if (result == 2) { 300 fprintf(stderr, "NSS-POLICY-FAIL\n"); 301 } else if (result == 1) { 302 fprintf(stderr, "NSS-POLICY-WARN\n"); 303 } 304 return result; 305 }