📄 cryptmis.c
字号:
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#ifndef EBCDIC_CHARS__
static const FAR_BSS BYTE asciiToBin[ 256 ] =
{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, 0x3E, BERR, BERR, BERR, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, BERR, BERR, BERR, BEOF, BERR, BERR,
BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, BERR, BERR, BERR, BERR, BERR,
BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR
};
#else
/* EBCDIC character mappings:
A-I C1-C9
J-R D1-D9
S-Z E2-E9
a-i 81-89
j-r 91-99
s-z A2-A9
0-9 F0-F9
+ 4E
/ 61
= 7E Uses BEOF in table */
static const FAR_BSS BYTE asciiToBin[ 256 ] =
{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*00*/
BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR, /* CR, LF */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*10*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*20*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*30*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*40*/
BERR, BERR, BERR, BERR, BERR, BERR, 0x3E, BERR, /* + */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*50*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x3F, BERR, BERR, BERR, BERR, BERR, BERR, /*60*/ /* / */
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*70*/
BERR, BERR, BERR, BERR, BERR, BERR, BEOF, BERR, /* = */
BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, /*80*/ /* a-i */
0x21, 0x22, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /*90*/ /* j-r */
0x2A, 0x2B, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, /*A0*/ /* s-z */
0x32, 0x33, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR, /*B0*/
BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*C0*/ /* A-I */
0x07, 0x08, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /*D0*/ /* J-R */
0x10, 0x11, BERR, BERR, BERR, BERR, BERR, BERR,
BERR, BERR, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /*E0*/ /* S-Z */
0x18, 0x19, BERR, BERR, BERR, BERR, BERR, BERR,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, /*F0*/ /* 0-9 */
0x3C, 0x3D, BERR, BERR, BERR, BERR, BERR, BERR
};
#endif /* Different character code mappings */
/* The size of lines for PEM-type formatting. This is only used for encoding,
for decoding we adjust to whatever size the sender has used */
#define TEXT_LINESIZE 64
#define BINARY_LINESIZE 48
/* Basic single-char en/decode functions. We cast the value to an unsigned
char to avoid generating negative array offsets if the sign bit is set,
since the strings are passed as char *'s */
#define encode(data) binToAscii[ ( BYTE ) data ]
#define decode(data) asciiToBin[ ( BYTE ) data ]
/* The headers and trailers used for base64-encoded certificate objects */
static const FAR_BSS struct {
const CRYPT_CERTTYPE_TYPE type;
const char *header, *trailer;
} headerInfo[] = {
{ CRYPT_CERTTYPE_CERTIFICATE,
"-----BEGIN CERTIFICATE-----" EOL,
"-----END CERTIFICATE-----" EOL },
{ CRYPT_CERTTYPE_ATTRIBUTE_CERT,
"-----BEGIN ATTRIBUTE CERTIFICATE-----" EOL,
"-----END ATTRIBUTE CERTIFICATE-----" EOL },
{ CRYPT_CERTTYPE_CERTCHAIN,
"-----BEGIN CERTIFICATE CHAIN-----" EOL,
"-----END CERTIFICATE CHAIN-----" EOL },
{ CRYPT_CERTTYPE_CERTREQUEST,
"-----BEGIN NEW CERTIFICATE REQUEST-----" EOL,
"-----END NEW CERTIFICATE REQUEST-----" EOL },
{ CRYPT_CERTTYPE_REQUEST_CERT,
"-----BEGIN NEW CERTIFICATE REQUEST-----" EOL,
"-----END NEW CERTIFICATE REQUEST-----" EOL },
{ CRYPT_CERTTYPE_CRL,
"-----BEGIN CERTIFICATE REVOCATION LIST-----" EOL,
"-----END CERTIFICATE REVOCATION LIST-----" EOL },
{ CRYPT_CERTTYPE_NONE, /* Universal catch-all */
"-----BEGIN CERTIFICATE OBJECT-----" EOL,
"-----END CERTIFICATE OBJECT-----" EOL }
};
/* Check whether a data item has a header that identifies it as some form of
encoded certificate object and return the start position of the encoded
data. For S/MIME certificate data this can in theory get quite complex
because there are many possible variations in the headers. Some early
S/MIME agents used a content type of "application/x-pkcs7-mime",
"application/x-pkcs7-signature", and "application/x-pkcs10", while newer
ones use the same without the "x-" at the start. In addition Netscape
have their own MIME data types for certificates, "application/x-x509-"
"{user-cert|ca-cert|email-cert}, and there are further types in the
endless stream of RFCs that PKIX churns out. There are a whole pile of
other possible headers as well, none of them terribly relevant for our
purposes, so all we check for is the base64 indicator. For PEM we just
check for the '-----..' header which is fairly simple. Finally we check
for raw base64-encoded data that can occur if an object is extracted from
a MIME message and the headers discarded */
static int readLine( STREAM *stream, char *buffer, const int maxSize )
{
MIME_STATE state;
int status;
initMIMEstate( &state, maxSize );
do
{
const int ch = sgetc( stream );
status = ( cryptStatusError( ch ) ) ? ch : \
addMIMEchar( &state, buffer, ch );
}
while( cryptStatusOK( status ) );
if( cryptStatusError( status ) && status != OK_SPECIAL )
return( status );
return( endMIMEstate( &state ) );
}
CRYPT_CERTFORMAT_TYPE base64checkHeader( const char *data,
const int dataLength, int *startPos )
{
STREAM stream;
BOOLEAN seenTransferEncoding = FALSE;
char buffer[ 1024 ];
int position, ch1, ch2, status;
/* Clear return value */
*startPos = 0;
/* If the item is too small to contain any useful data, we don't even try
and examine it */
if( dataLength < 64 )
return( CRYPT_CERTFORMAT_NONE );
sMemConnect( &stream, data, dataLength );
/* Sometimes the object can be preceded by a few blank lines. We're
fairly lenient with this */
do
ch1 = sgetc( &stream );
while( ch1 == '\r' || ch1 == '\n' );
ch2 = sgetc( &stream );
position = stell( &stream ) - 2;
/* Perform a quick check to weed out non-encoded cert data, which is
usually the case */
if( ( ch1 == 0x30 ) && ( !isAlpha( ch2 ) || \
!isAlpha( sgetc( &stream ) ) || \
!isAlpha( sgetc( &stream ) ) ) )
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
sseek( &stream, position );
/* If it starts with a dash, check for PEM header encapsulation */
if( ch1 == '-' )
{
int i;
/* We always have to start with 5 dashes and 'BEGIN '. After this
there can be all sorts of stuff, but it has to end with another
five dashes and a newline */
if( cryptStatusError( sread( &stream, buffer, 11 ) ) || \
memcmp( buffer, "-----BEGIN ", 11 ) )
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
for( i = 0; i < 40; i++ )
if( sgetc( &stream ) == '-' )
break;
if( i == 40 )
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
if( cryptStatusError( sread( &stream, buffer, 4 ) ) || \
memcmp( buffer, "----", 4 ) )
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
ch1 = sgetc( &stream );
if( ch1 != '\n' )
{
if( ch1 == '\r' )
{
if( sPeek( &stream ) == '\n' )
sgetc( &stream );
}
else
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
}
/* Return the start position of the payload */
*startPos = stell( &stream );
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_TEXT_CERTIFICATE );
}
/* It's not PEM header encapsulation, check for raw base64 containing
some form of encoded cert. There isn't a 100% reliable check for
this, but if the first 60 chars (the minimum base64 line length) are
all valid base64 chars and the first chars match the required values
then it's reasonably certain that it's base64 cert data.
First we do a quick check to see if the content is some form of
encoded cert. For cert data that begins with 30 8x, the
corresponding base64 values are MI... */
if( ch1 == 'M' && ch2 == 'I' )
{
BOOLEAN base64OK = TRUE;
int i;
/* It looks like an encoded cert, make sure that it's really base64
data */
for( i = 0; i < 15; i++ )
{
status = sread( &stream, buffer, 4 );
if( cryptStatusError( status ) )
{
base64OK = FALSE;
break;
}
else
{
const BYTE c0 = decode( buffer[ 0 ] );
const BYTE c1 = decode( buffer[ 1 ] );
const BYTE c2 = decode( buffer[ 2 ] );
const BYTE c3 = decode( buffer[ 3 ] );
const BYTE cx = c0 | c1 | c2 | c3;
if( cx == BEOF || cx == BERR )
{
base64OK = FALSE;
break;
}
}
}
/* If everything was OK, it's raw base64 */
if( base64OK )
{
sMemDisconnect( &stream );
*startPos = position;
return( CRYPT_CERTFORMAT_TEXT_CERTIFICATE );
}
}
sseek( &stream, position );
/* It doesn't look like raw base64, check for an S/MIME header */
do
{
status = readLine( &stream, buffer, 1024 );
if( !cryptStatusError( status ) && status >= 32 && \
strCompare( buffer, "Content-Transfer-Encoding: bas64", 32 ) )
seenTransferEncoding = TRUE;
}
while( status > 0 );
if( cryptStatusError( status ) || !seenTransferEncoding )
{
sMemDisconnect( &stream );
return( CRYPT_CERTFORMAT_NONE );
}
/* Skip trailing blank lines */
do
ch1 = sgetc( &stream );
while( ch1 == '\r' || ch1 == '\n' );
/* Make sure that the content is some form of encoded cert. For cert
data that begins with 30 8x, the corredponding base64 values are
MI... */
*startPos = stell( &stream ) - 1;
status = CRYPT_ICERTFORMAT_SMIME_CERTIFICATE;
if( ch1 != 'M' || sgetc( &stream ) != 'I' )
status = CRYPT_CERTFORMAT_NONE;
sMemDisconnect( &stream );
return( status );
}
/* Encode a block of binary data into the base64 format, returning the total
number of output bytes */
int base64encode( char *outBuffer, const void *inBuffer, const int count,
const CRYPT_CERTTYPE_TYPE certType )
{
BYTE *inBufferPtr = ( BYTE * ) inBuffer;
int srcIndex = 0, destIndex = 0, lineCount = 0, remainder = count % 3;
int headerInfoIndex;
/* If it's a certificate object, add the header */
if( certType != CRYPT_CERTTYPE_NONE )
{
for( headerInfoIndex = 0;
headerInfo[ headerInfoIndex ].type != certType && \
headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE;
headerInfoIndex++ );
assert( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
strcpy( outBuffer, headerInfo[ headerInfoIndex ].header );
destIndex = strlen( headerInfo[ headerInfoIndex ].header );
}
/* Encode the data */
while( srcIndex < count )
{
/* If we've reached the end of a line of binary data and it's a
certificate, add the EOL marker */
if( certType != CRYPT_CERTTYPE_NONE && lineCount == BINARY_LINESIZE )
{
strcpy( outBuffer + destIndex, EOL );
destIndex += EOL_LEN;
lineCount = 0;
}
lineCount += 3;
/* Encode a block of data from the input buffer */
outBuffer[ destIndex++ ] = encode( inBufferPtr[ srcIndex ] >> 2 );
outBuffer[ destIndex++ ] = encode( ( ( inBufferPtr[ srcIndex ] << 4 ) & 0x30 ) |
( ( inBufferPtr[ srcIndex + 1 ] >> 4 ) & 0x0F ) );
srcIndex++;
outBuffer[ destIndex++ ] = encode( ( ( inBufferPtr[ srcIndex ] <
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -