static int serverTransact( INOUT SESSION_INFO *sessionInfoPtr ) { SCEP_PROTOCOL_INFO protocolInfo; HTTP_DATA_INFO httpDataInfo; HTTP_URI_INFO httpReqInfo; BOOLEAN requestDataOK; int requestCount, length = DUMMY_INIT, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); /* SCEP is a weird protocol that started out as a basic IPsec certificate-provisioning mechanism for routers but then had a pile of additional functionality bolted onto it via HTTP mechanisms rather than having the protocol itself handle the extra functionality. Because of this we have to handle not only the standard HTTP-as-a- substrate mechanism used by the other protocols but also HTTP GET requests for additional information that the original protocol didn't accomodate */ sessionInfoPtr->receiveBufEnd = 0; sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_HTTPREQTYPES, STREAM_HTTPREQTYPE_ANY ); for( requestCount = 0; requestCount < 5; requestCount++ ) { initHttpDataInfoEx( &httpDataInfo, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &httpReqInfo ); status = sread( &sessionInfoPtr->stream, &httpDataInfo, sizeof( HTTP_DATA_INFO ) ); if( cryptStatusError( status ) ) { sNetGetErrorInfo( &sessionInfoPtr->stream, &sessionInfoPtr->errorInfo ); return( status ); } /* If it's a proper SCEP protocol message, switch back to handling the main protocol */ if( httpDataInfo.reqType != STREAM_HTTPREQTYPE_GET ) { sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_HTTPREQTYPES, STREAM_HTTPREQTYPE_POST ); length = httpDataInfo.bytesAvail; break; } /* It's one of the bolted-on additions to the basic SCEP protocol, handle it specially */ status = processAdditionalScepRequest( sessionInfoPtr, &httpReqInfo ); if( cryptStatusError( status ) ) return( status ); } if( requestCount >= 5 ) { /* The exact type of error response to send at this point is a bit tricky, the least inappropriate one is probably CRYPT_ERROR_DUPLICATE to indicate that too many duplicate requests were sent, since to get here the client would have had to send repeated identical bolt-on requests */ sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_DUPLICATE ); return( CRYPT_ERROR_OVERFLOW ); } /* Unfortunately we can't use readPkiDatagram() because of the weird dual-purpose HTTP transport used in SCEP so we have to duplicate portions of readPkiDatagram() here. See the readPkiDatagram() function for code comments explaining the following operations */ if( length < 4 || length >= MAX_INTLENGTH ) { sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA ); retExt( CRYPT_ERROR_UNDERFLOW, ( CRYPT_ERROR_UNDERFLOW, SESSION_ERRINFO, "Invalid PKI message length %d", length ) ); } status = length = \ checkObjectEncoding( sessionInfoPtr->receiveBuffer, length ); if( cryptStatusError( status ) ) { sendCertErrorResponse( sessionInfoPtr, CRYPT_ERROR_BADDATA ); retExt( status, ( status, SESSION_ERRINFO, "Invalid PKI message encoding" ) ); } sessionInfoPtr->receiveBufEnd = length; /* Process the initial message from the client */ initSCEPprotocolInfo( &protocolInfo ); status = checkScepRequest( sessionInfoPtr, &protocolInfo, &requestDataOK ); if( cryptStatusError( status ) ) { /* If we got far enough into the request data to be able to send a SCEP-level response, send that, otherwise just send an HTTP-level response */ if( requestDataOK ) sendErrorResponse( sessionInfoPtr, &protocolInfo, status ); else sendCertErrorResponse( sessionInfoPtr, status ); return( status ); } /* Issue a certificate from the request */ status = issueCertFromRequest( sessionInfoPtr, &protocolInfo ); if( cryptStatusError( status ) ) { sendErrorResponse( sessionInfoPtr, &protocolInfo, status ); destroySCEPprotocolInfo( &protocolInfo ); return( status ); } /* Return the certificate to the client */ status = createScepResponse( sessionInfoPtr, &protocolInfo ); if( cryptStatusOK( status ) ) status = writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, SCEP_CONTENT_TYPE_LEN ); destroySCEPprotocolInfo( &protocolInfo ); return( status ); }
IN_LENGTH const int objectLength, IN_HANDLE const CRYPT_CONTEXT iSignContext, IN_ALGO const CRYPT_ALGO_TYPE hashAlgo, IN_OPT const X509SIG_FORMATINFO *formatInfo ) { CRYPT_CONTEXT iHashContext; MESSAGE_CREATEOBJECT_INFO createInfo; STREAM stream; BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ]; int signatureLength, totalSigLength, status; assert( signedObject == NULL || \ isWritePtr( signedObject, signedObjectMaxLength ) ); assert( isWritePtr( signedObjectLength, sizeof( int ) ) ); assert( isReadPtr( object, objectLength ) && \ !cryptStatusError( checkObjectEncoding( object, \ objectLength ) ) ); assert( formatInfo == NULL || \ isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) ); REQUIRES( ( signedObject == NULL && signedObjectMaxLength == 0 ) || \ ( signedObject != NULL && \ signedObjectMaxLength > MIN_CRYPT_OBJECTSIZE && \ signedObjectMaxLength < MAX_INTLENGTH ) ); REQUIRES( objectLength > 0 && objectLength < MAX_INTLENGTH ); REQUIRES( isHandleRangeValid( iSignContext ) ); REQUIRES( isHashAlgo( hashAlgo ) ); REQUIRES( formatInfo == NULL || \ ( ( formatInfo->tag >= 0 && \ formatInfo->tag < MAX_CTAG_VALUE ) && \ ( formatInfo->extraLength >= 0 && \ formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );