12 #if defined( __MVS__ ) || defined( __VMCMS__ )
14 #pragma convlit( suspend )
16 #if defined( __ILEC400__ )
28 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && !defined( NDEBUG )
29 #define EXPIRY_WARN_DAYS 90
31 #define EXPIRY_WARN_DAYS 30
45 static char *getTimeString(
const time_t theTime,
const int bufNo )
47 static char timeString[ 2 ][ 64 ], *timeStringPtr;
49 assert( bufNo == 0 || bufNo == 1 );
51 timeStringPtr = ctime( &theTime );
52 if( timeStringPtr == NULL )
53 return(
"(Not available)" );
54 strcpy( timeString[ bufNo ], timeStringPtr );
55 timeString[ bufNo ][ strlen( timeStringPtr ) - 1 ] =
'\0';
57 return( timeString[ bufNo ] );
60 #define getTimeString( theTime, bufNo ) "(No time data available)"
63 #if defined( _WIN32_WCE ) && _WIN32_WCE < 500
65 int remove(
const char *pathname )
69 mbstowcs( wcBuffer, pathname, strlen( pathname ) + 1 );
70 DeleteFile( wcBuffer );
97 printf(
"Couldn't access cryptlib keyset file %s. Please make "
98 "sure\nthat all the cryptlib files have been installed "
99 "correctly, and the cryptlib\nself-test is being run from "
108 if( ( filePtr = fopen( buffer,
"rb" ) ) == NULL )
110 puts(
"Couldn't open binary data test file to check for data "
111 "conversion problems." );
116 if( length != 16 || \
117 memcmp( buffer,
"\x30\x82\x02\x56\x30\x82\x02\x52\r\n\x08\x40\n" "tqz", 16 ) )
119 puts(
"Binary data is corrupt, probably due to being unzipped or "
120 "copied onto the\nsystem in a mode that tries to translate "
121 "text data during processing/copying." );
126 if( ( filePtr = fopen( buffer,
"rb" ) ) == NULL )
128 puts(
"Couldn't open text data test file to check for data "
129 "conversion problems." );
134 if( length != 10 || memcmp( buffer,
"test\ntest\n" , 10 ) )
136 puts(
"Text data is still in CRLF-delimited format, probably due "
137 "to being unzipped\nwithout the '-a' option to translate "
138 "text files for Unix systems." );
154 printf(
"Couldn't access cryptlib keyset file %s even though the "
155 "file\nexists and is readable. Please make sure that the "
156 "cryptlib self-test is\nbeing run from the correct "
208 const C_STR fileTemplate,
const int number )
211 #ifdef UNICODE_STRINGS
216 #ifdef UNICODE_STRINGS
217 mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
227 const C_STR keyName )
240 printExtError( cryptKeyset,
"cryptGetPublicKey", status, __LINE__ );
249 time_t validFrom, validTo;
260 printExtError( cryptKeyset,
"cryptGetPrivateKey", status, __LINE__ );
284 const time_t currentTime = time( NULL );
286 puts(
" ********************" );
287 if( validTo <= currentTime )
289 puts(
"Warning: This key has expired. Certificate-related "
290 "operations will fail or\n result in error "
291 "messages from the test code." );
295 if( validTo - currentTime <= 86400 )
297 puts(
"Warning: This key expires today. Certificate-"
298 "related operations may fail\n or result in "
299 "error messages from the test code." );
303 printf(
"Warning: This key will expire in %ld days. "
304 "Certificate-related operations\n may fail "
305 "or result in error messages from the test code.\n",
306 ( validTo - currentTime ) / 86400 );
309 puts(
" ********************" );
310 printf(
"Hit a key..." );
348 return(
TEXT(
"notfound" ) );
360 return(
TEXT(
"test1" ) );
362 return(
TEXT(
"test10" ) );
364 return(
TEXT(
"testkey" ) );
366 return(
TEXT(
"def" ) );
369 return(
TEXT(
"notfound" ) );
383 return(
TEXT(
"test" ) );
385 return(
TEXT(
"suzuki" ) );
387 return( isPrivKey ?
TEXT(
"test" ) :
TEXT(
"test cryptlib" ) );
390 return(
TEXT(
"test1" ) );
392 return(
TEXT(
"Max Mustermann" ) );
395 return(
TEXT(
"notfound" ) );
404 #if defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x310 )
409 size_t mbstowcs(
char *pwcs,
const char *
s,
size_t n )
411 memcpy( pwcs, s, n );
421 #if defined( UNIX_THREADS ) || defined( WINDOWS_THREADS ) || defined( OS2_THREADS )
423 #if defined( UNIX_THREADS )
426 #include <sys/time.h>
431 #if defined( UNIX_THREADS )
432 struct timeval tv = { 0 };
438 select( 1, NULL, NULL, NULL, &tv );
439 #elif defined( WINDOWS_THREADS )
440 Sleep( seconds * 1000 );
450 void wcPrintf(
const char *format, ... )
452 wchar_t wcBuffer[ 1024 ];
456 va_start( argPtr, format );
457 vsprintf( buffer, format, argPtr );
459 mbstowcs( wcBuffer, buffer, strlen( buffer ) + 1 );
460 NKDbgPrintfW( wcBuffer );
463 void wcPuts(
const char *
string )
465 wcPrintf(
"%s\n",
string );
472 #ifdef UNICODE_STRINGS
480 wcstombs( fileNameBuffer, fileName, wcslen( fileName ) + 1 );
481 return( fileNameBuffer );
495 wcstombs( buffer, wcBuffer, length + 1 );
499 const wchar_t *fileTemplate,
512 #if defined( WINDOWS_THREADS )
518 hMutex = CreateMutex( NULL,
FALSE, NULL );
522 if( WaitForSingleObject( hMutex, 30000 ) == WAIT_TIMEOUT )
524 puts(
"Warning: Couldn't acquire mutex after 30s wait. Press a "
525 "key to continue." );
531 if( WaitForSingleObject( hMutex, 30000 ) == WAIT_TIMEOUT )
542 if( !ReleaseMutex( hMutex ) )
544 puts(
"Warning: Couldn't release mutex. Press a key to continue." );
550 CloseHandle( hMutex );
555 if( WaitForSingleObject( hThread, 15000 ) == WAIT_TIMEOUT )
557 puts(
"Warning: Server thread is still active due to session "
558 "negotiation failure,\n this will cause an error "
559 "condition when cryptEnd() is called due\n to "
560 "resources remaining allocated. Press a key to continue." );
563 CloseHandle( hThread );
565 #elif defined( UNIX_THREADS )
567 static pthread_mutex_t mutex;
571 pthread_mutex_init( &mutex, NULL );
575 pthread_mutex_lock( &mutex );
579 pthread_mutex_lock( &mutex );
589 pthread_mutex_unlock( &mutex );
593 pthread_mutex_destroy( &mutex );
598 if( pthread_join( hThread, NULL ) < 0 )
600 puts(
"Warning: Server thread is still active due to session "
601 "negotiation failure,\n this will cause an error "
602 "condition when cryptEnd() is called due\n to "
603 "resources remaining allocated. Press a key to continue." );
628 #if defined( WINDOWS_THREADS ) || defined( UNIX_THREADS )
648 for( i = 0; i < noThreads; i++ )
650 #ifdef WINDOWS_THREADS
651 unsigned int threadID;
653 hServerThreads[ i ] = (
HANDLE ) \
654 _beginthreadex( NULL, 0, serverFunction,
655 &sessionID[ i ], 0, &threadID );
657 pthread_t threadHandle;
659 hServerThreads[ i ] = 0;
660 if( pthread_create( &threadHandle, NULL, serverFunction,
661 &sessionID[ i ] ) == 0 )
662 hServerThreads[ i ] = threadHandle;
668 for( i = 0; i < noThreads; i++ )
670 #ifdef WINDOWS_THREADS
671 unsigned int threadID;
673 hClientThreads[ i ] = (
HANDLE ) \
674 _beginthreadex( NULL, 0, clientFunction,
675 &sessionID[ i ], 0, &threadID );
677 pthread_t threadHandle;
679 hServerThreads[ i ] = 0;
680 if( pthread_create( &threadHandle, NULL, clientFunction,
681 &sessionID[ i ] ) == 0 )
682 hClientThreads[ i ] = threadHandle;
685 #ifdef WINDOWS_THREADS
686 if( WaitForMultipleObjects( noThreads, hServerThreads,
TRUE,
687 60000 ) == WAIT_TIMEOUT || \
688 WaitForMultipleObjects( noThreads, hClientThreads,
TRUE,
689 60000 ) == WAIT_TIMEOUT )
694 pthread_join( hServerThreads[ 0 ], NULL );
695 pthread_join( hClientThreads[ 0 ], NULL );
698 puts(
"Warning: Server threads are still active due to session "
699 "negotiation failure,\n this will cause an error "
700 "condition when cryptEnd() is called due\n to "
701 "resources remaining allocated. Press a key to continue." );
704 #ifdef WINDOWS_THREADS
705 for( i = 0; i < noThreads; i++ )
706 if( hServerThreads[ i ] != 0 )
707 CloseHandle( hServerThreads[ i ] );
708 for( i = 0; i < noThreads; i++ )
709 if( hClientThreads[ i ] != 0 )
710 CloseHandle( hClientThreads[ i ] );
727 int errorType, errorLocus,
status;
734 printf(
" Error info attributes report locus %d, type %d.\n",
735 errorLocus, errorType );
745 char errorMessage[ 512 ];
746 int errorMessageLength,
status;
748 printf(
"%s failed with error code %d, line %d.\n", functionName,
749 functionStatus, lineNo );
751 errorMessage, &errorMessageLength );
754 puts(
" No extended error information available." );
758 errorMessage[ errorMessageLength ] =
'\0';
759 printf(
" Error message = %s'%s'.\n",
760 ( errorMessageLength > ( 80 - 21 ) ) ?
"\n " :
"",
770 const int lineNumber )
772 printf(
"%s failed with error code %d, line %d.\n", functionName,
773 errorCode, lineNumber );
780 const int lineNumber )
782 printExtError( cryptHandle, functionName, errorCode, lineNumber );
815 const CERT_DATA *certData,
const int lineNo )
830 printf(
"cryptSetAttribute() for entry %d, field ID %d,\n"
831 " value %d, failed with error code %d, line %d.\n",
832 i + 1, certData[ i ].type, certData[ i ].numericValue,
839 certData[ i ].type, certData[ i ].stringValue,
840 certData[ i ].numericValue ? \
841 certData[ i ].numericValue : \
845 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && !defined( NDEBUG )
848 !memcmp( certData[ i ].stringValue,
"NZ", 2 ) )
851 puts(
" ********************" );
852 puts(
"If you're running this under BoundsChecker "
853 "you need to disable it to complete\nthe test "
854 "since it causes errors in the certificate "
855 "string-checking code. The\nfollowing error "
856 "is caused by BoundsChecker, not by the "
857 "self-test failing." );
858 puts(
" ********************" );
861 printf(
"cryptSetAttributeString() for entry %d, field ID %d,\n"
862 " value '%s', failed with error code %d, line %d.\n",
863 i + 1, certData[ i ].type,
864 (
char * ) certData[ i ].stringValue, status,
872 certData[ i ].type, certData[ i ].stringValue,
873 wcslen( certData[ i ].stringValue ) *
sizeof(
wchar_t ) );
876 printf(
"cryptSetAttributeString() for entry %d, field ID %d,\n"
877 " value '%s', failed with error code %d, line %d.\n",
878 i + 1, certData[ i ].type,
879 (
char * ) certData[ i ].stringValue, status,
887 certData[ i ].type, &certData[ i ].timeValue,
890 printf(
"cryptSetAttributeString() for entry %d, field ID %d,\n"
891 " value 0x%lX, failed with error code %d, line %d.\n",
892 i + 1, certData[ i ].type, certData[ i ].timeValue,
914 #if defined( _MSC_VER ) && defined( _WIN32 ) && !defined( _WIN32_WCE ) && 0
916 void loadCertificates(
void )
918 WIN32_FIND_DATA findData;
921 searchHandle = FindFirstFile(
"d:/tmp/certs/*.der", &findData );
922 if( searchHandle == INVALID_HANDLE_VALUE )
929 printf(
"Adding certificate %s.\n", findData.cFileName );
936 while( FindNextFile( searchHandle, &findData ) );
937 FindClose( searchHandle );
949 #if defined( _MSC_VER ) && \
950 !( defined( _WIN32_WCE ) || defined( __PALMSOURCE__ ) )
959 const char *tmpPath = getenv(
"TMPDIR" );
961 const int tmpPathLen = ( tmpPath != NULL ) ? strlen( tmpPath ) : 0;
963 char fileNameBuffer[ 128 ];
965 const int length = strlen( fileName );
968 fileNameBuffer[ 0 ] =
'\0';
969 #if defined( _WIN32_WCE )
973 #elif ( defined( _MSC_VER ) && !defined( __PALMSOURCE__ ) )
981 #if defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
982 #pragma comment(linker, "/nodefaultlib:oldnames.lib")
984 if( fileName[ 1 ] !=
':' )
986 if( _access(
"d:/tmp/", 6 ) == 0 )
989 if( _access(
"d:/tmp/", 6 ) == -1 && \
990 !CreateDirectory(
"d:/tmp", NULL ) )
992 strcpy( fileNameBuffer,
"d:/tmp/" );
998 if( _access(
"c:/tmp/", 6 ) == -1 && \
999 !CreateDirectory(
"c:/tmp", NULL ) )
1001 strcpy( fileNameBuffer,
"c:/tmp/" );
1004 #elif defined( __UNIX__ )
1006 if( fileName[ 0 ] !=
'/' )
1010 strcpy( fileNameBuffer, tmpPath );
1011 if( fileNameBuffer[ tmpPathLen - 1 ] !=
'/' )
1012 strcat( fileNameBuffer + tmpPathLen,
"/" );
1015 strcpy( fileNameBuffer,
"/tmp/" );
1018 fileNameBuffer[ 0 ] =
'\0';
1020 strcat( fileNameBuffer, fileName );
1021 if( length <= 3 || fileName[ length - 4 ] !=
'.' )
1022 strcat( fileNameBuffer,
".der" );
1024 #if defined( __VMCMS__ )
1026 char formatBuffer[ 32 ];
1028 sprintf( formatBuffer,
"wb, recfm=F, lrecl=%d, noseek", dataLength );
1029 filePtr = fopen( fileNameBuffer, formatBuffer );
1031 if( filePtr == NULL )
1033 if( ( filePtr = fopen( fileNameBuffer,
"wb" ) ) == NULL )
1036 count = fwrite( data, 1, dataLength, filePtr );
1038 if( count < length )
1040 printf(
"Warning: Couldn't dump '%s' to disk.\n", fileName );
1055 #ifndef UNICODE_STRINGS
1058 C_CHR serverName[ 128 ];
1059 int serverNameLength, serverPort,
status;
1062 serverName, &serverNameLength );
1066 #ifdef UNICODE_STRINGS
1067 serverName[ serverNameLength /
sizeof(
wchar_t ) ] =
TEXT(
'\0' );
1068 printf(
"SVR: Connect attempt from %S, port %d", serverName, serverPort );
1070 serverName[ serverNameLength ] =
'\0';
1072 printf(
"SVR: Connect attempt from %s, port %d, on %s.\n", serverName,
1073 serverPort, getTimeString( theTime, 0 ) );
1087 const BOOLEAN showFingerprint,
1088 const BOOLEAN showServerKeyInfo,
1089 const BOOLEAN showClientCertInfo )
1104 printf(
"Couldn't get session security parameters, status %d, line "
1105 "%d.\n", status, __LINE__ );
1108 printf(
"%sSession is protected using algorithm %d with a %d bit key,\n"
1109 " protocol version %d.\n", isServer ?
"SVR: " :
"",
1110 cryptAlgo, keySize * 8, version );
1111 if( showServerKeyInfo || showClientCertInfo )
1128 printf(
"Couldn't get server security parameters, status %d, line "
1129 "%d.\n", status, __LINE__ );
1132 printf(
"%s key uses algorithm %d, key size %d bits.\n",
1133 showClientCertInfo ?
"SVR: Client authentication" :
"Server",
1134 cryptAlgo, keySize * 8 );
1137 if( isServer || !showFingerprint )
1154 fingerPrint, &length );
1157 printf(
"cryptGetAttributeString() failed with error code "
1158 "%d, line %d.\n", status, __LINE__ );
1161 printf(
"%sServer key fingerprint =\n ", isServer ?
"SVR: " :
"" );
1162 for( i = 0; i <
length; i++ )
1166 printf(
"%02X", fingerPrint[ i ] );
1185 #define LOCAL_HOST_NAME "localhost"
1187 #define LOCAL_HOST_NAME "192.168.1.45"
1196 puts(
"Warning: Enabling server on non-local interface '"
1216 ( ( port / 100 ) * 1000 ) + port );
1221 printf(
"cryptSetAttribute/AttributeString() failed with error code "
1222 "%d, line %d.\n", status, __LINE__ );
1232 static void printOperationType(
const CRYPT_SESSION cryptSession )
1235 const int operation;
1237 } operationTypeTbl[] = {
1255 userID, &userIDsize );
1258 printf(
"cryptGetAttribute/AttributeString() failed with error "
1259 "code %d, line %d.\n", status, __LINE__ );
1262 userID[ userIDsize ] =
'\0';
1263 for( i = 0; operationTypeTbl[ i ].operation != requestType && \
1264 operationTypeTbl[ i ].operation != -1; i++ );
1265 printf(
"SVR: Operation type was %d = %s, user '%s'.\n",
1266 requestType, operationTypeTbl[ i ].
name, userID );
1271 const BOOLEAN showOperationType )
1293 printOperationType( cryptSession );
1295 &connectionActive );
1319 puts(
"Attributes present (by cryptlib ID) are:" );
1329 printf(
"\nCurrent attribute group value read failed with "
1330 "error code %d, line %d.\n", status, __LINE__ );
1333 printf(
" Attribute group %d, values =", value );
1340 printf(
"\nCurrent attribute value read failed with error "
1341 "code %d, line %d.\n", status, __LINE__ );
1346 printf(
" %d", value );
1374 wchar_t wcValue[ 8 + 4 ];
1378 if( ( length %
sizeof(
wchar_t ) ) || length <=
sizeof(
wchar_t ) * 2 )
1383 if( isprint( value[ 0 ] ) && isprint( value[ 1 ] ) && \
1384 isprint( value[ 2 ] ) && isprint( value[ 3 ] ) )
1389 memcpy( wcValue, value,
min( 8, length ) );
1395 if( ( wcValue[ 0 ] & 0xFF00 ) == ( wcValue[ 1 ] & 0xFF00 ) && \
1396 ( wcValue[ 0 ] & 0xFF00 ) == ( wcValue[ 2 ] & 0xFF00 ) )
1404 static void printHex(
const BYTE *value,
const int length )
1408 for( i = 0; i <
length; i++ )
1412 printf(
"%02X", value[ i ] );
1421 #define CHK( function ) \
1422 status = function; \
1423 if( cryptStatusError( status ) ) \
1424 return( certInfoErrorExit( #function, status, __LINE__ ) )
1426 static int certInfoErrorExit(
const char *functionCall,
const int status,
1429 printf(
"\n%s failed with status %d, line %d.\n", functionCall,
1438 const char *prefixString )
1440 char buffer[ 1024 + 1 ];
1451 puts(
" (Name contains characters that prevent it from being "
1452 "represented as a\n text string)." );
1460 puts(
" (Name is too long to display, > 1K characters)." );
1467 if( isUnicode( buffer, length ) )
1469 wchar_t wcBuffer[ 1024 + 1 ];
1473 memcpy( wcBuffer, buffer, length );
1474 wcBuffer[ length /
sizeof(
wchar_t ) ] =
TEXT(
'\0' );
1475 printf(
" %s = %S.\n", prefixString, wcBuffer );
1479 printf(
" %s = %s.\n", prefixString, buffer );
1486 const char *prefixString )
1491 if( !printComponent( certificate, component, prefixString ) )
1510 sprintf( buffer,
" + %s", prefixString );
1511 if( !printComponent( certificate, component, buffer ) )
1543 printf(
" altName DN is:\n" );
1544 printDN( certificate );
1553 char buffer[ 1024 ];
1569 puts(
"Certificate object issuer name is:" );
1572 printDN( certificate );
1579 printAltName( certificate );
1590 puts(
"Certificate object subject name is:" );
1593 printDN( certificate );
1600 printAltName( certificate );
1610 time_t validFrom, validTo;
1613 &validFrom, &length ) );
1615 &validTo, &length ) );
1616 printf(
"Certificate is valid from %s to %s.\n",
1617 getTimeString( validFrom, 0 ),
1618 getTimeString( validTo, 1 ) );
1622 time_t thisUpdate, nextUpdate;
1625 &thisUpdate, &length );
1632 &nextUpdate, &length );
1635 printf(
"OCSP source CRL time %s,\n next update %s.\n",
1636 getTimeString( thisUpdate, 0 ),
1637 getTimeString( nextUpdate, 1 ) );
1641 printf(
"OCSP source CRL time %s.\n",
1642 getTimeString( thisUpdate, 0 ) );
1648 time_t thisUpdate, nextUpdate;
1651 &thisUpdate, &length ) );
1653 &nextUpdate, &length );
1656 printf(
"CRL time %s,\n next update %s.\n",
1657 getTimeString( thisUpdate, 0 ),
1658 getTimeString( nextUpdate, 1 ) );
1661 printf(
"CRL time %s.\n", getTimeString( thisUpdate, 0 ) );
1674 puts(
"Revocation/validity list information: " );
1678 time_t timeStamp = 0;
1680 int revStatus, certStatus;
1710 if( noEntries >= 20 )
1712 if( noEntries == 20 )
1713 puts(
" (Further entries exist, but won't be printed)." );
1721 printf(
" Certificate status = %d (%s).\n",
1728 "only non-authoritative response available" : \
1733 printf(
" Entry %d, rev.status = %d (%s), rev.time "
1734 "%s.\n", noEntries, revStatus,
1738 "revoked" :
"unknown",
1739 getTimeString( timeStamp, 0 ) );
1743 printf(
" Entry %d, revocation time %s.\n", noEntries,
1744 getTimeString( timeStamp, 0 ) );
1755 printf(
"Revocation/validity list has %d entr%s.\n", noEntries,
1756 ( noEntries == 1 ) ?
"y" :
"ies" );
1762 printf(
"Certificate object is %sself-signed.\n",
1763 value ?
"" :
"not " );
1768 buffer, &length ) );
1769 printf(
"Certificate fingerprint = " );
1770 printHex( buffer, length );
1782 puts(
" (No extensions/attributes)." );
1785 puts(
"Some of the common extensions/attributes are:" );
1795 printf(
" crlNumber = %d.\n", value );
1799 printf(
" deltaCRLIndicator = %d.\n", value );
1803 printf(
" crlReason = %d.\n", value );
1808 printf(
" invalidityDate = %s.\n",
1809 getTimeString( theTime, 0 ) );
1817 puts(
" issuingDistributionPoint is:" );
1818 printDN( certificate );
1819 printAltName( certificate );
1830 &signingTime, &length );
1832 printf(
"Signing time %s.\n", getTimeString( signingTime, 0 ) );
1839 buffer, &length ) );
1841 printf(
" PKI user ID = %s.\n", buffer );
1844 buffer, &length ) );
1846 printf(
" PKI user issue password = %s.\n", buffer );
1849 buffer, &length ) );
1851 printf(
" PKI user revocation password = %s.\n", buffer );
1858 static const struct {
int flag;
const char *
name; } usageNames[] = {
1873 printf(
" keyUsage = %02X (", value );
1876 if( usageNames[ i ].flag & value )
1880 printf(
"%s", usageNames[ i ].
name );
1881 printedUsage =
TRUE;
1892 printf(
" extKeyUsage types = " );
1899 printf(
"%s%d", firstTime ?
"" :
", ", value );
1908 printf(
" basicConstraints.cA = %s.\n", value ?
"True" :
"False" );
1912 printf(
" basicConstraints.pathLenConstraint = %d.\n", value );
1917 printf(
" subjectKeyIdentifier = " );
1918 printHex( buffer, length );
1924 printf(
" authorityKeyIdentifier = " );
1925 printHex( buffer, length );
1932 printf(
" certificatePolicies.policyInformation.policyIdentifier = "
1939 printf(
" certificatePolicies.policyInformation.cpsURI = "
1947 printf(
" certificatePolicies.policyInformation.organisation = "
1955 printf(
" certificatePolicies.policyInformation.explicitText = "
1965 puts(
" crlDistributionPoint is/are:" );
1968 printDN( certificate );
1969 printAltName( certificate );
1998 printf(
"Certificate %d\n-------------\n", count++ );