mwelch%netscape.com 18749490fd Bringing tip of PSM client lib up to date with changes from commercial tip
git-svn-id: svn://10.0.0.236/trunk@67057 18797224-902f-48f8-a5cc-f745e15eee43
2000-04-25 02:57:11 +00:00

637 lines
17 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifdef XP_UNIX
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#else
#ifdef XP_MAC
#include "macsocket.h"
#else /* Windows */
#include <windows.h>
#include <winsock.h>
#endif
#endif
#include <errno.h>
#include "cmtcmn.h"
#include "cmtutils.h"
#include "messages.h"
#include "rsrcids.h"
typedef struct _CMTP7Private {
CMTPrivate priv;
CMTP7ContentCallback cb;
void *cb_arg;
} CMTP7Private;
CMTStatus CMT_PKCS7DecoderStart(PCMT_CONTROL control, void* clientContext, CMUint32 * connectionID, CMInt32 * result,
CMTP7ContentCallback cb, void *cb_arg)
{
CMTItem message;
CMTStatus rv;
CMTP7Private *priv=NULL;
SingleItemMessage request;
DataConnectionReply reply;
/* Check passed in parameters */
if (!control) {
goto loser;
}
request.item = CMT_CopyPtrToItem(clientContext);
/* Encode message */
if (CMT_EncodeMessage(SingleItemMessageTemplate, &message, &request) != CMTSuccess) {
goto loser;
}
/* Set the message request type */
message.type = SSM_REQUEST_MESSAGE | SSM_DATA_CONNECTION | SSM_PKCS7DECODE_STREAM;
/* Send the message. */
if (CMT_SendMessage(control, &message) == CMTFailure) {
goto loser;
}
/* Validate the message reply type */
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_DATA_CONNECTION | SSM_PKCS7DECODE_STREAM)) {
goto loser;
}
/* Decode the reply */
if (CMT_DecodeMessage(DataConnectionReplyTemplate, &reply, &message) != CMTSuccess) {
goto loser;
}
/* Success */
if (reply.result == 0) {
CMTSocket sock;
priv = (CMTP7Private *)malloc(sizeof(CMTP7Private));
if (priv == NULL)
goto loser;
priv->priv.dest = (CMTReclaimFunc) free;
priv->cb = cb;
priv->cb_arg = cb_arg;
sock = control->sockFuncs.socket(0);
if (sock == NULL) {
goto loser;
}
if (control->sockFuncs.connect(sock, (short)reply.port,
NULL) != CMTSuccess) {
goto loser;
}
if (control->sockFuncs.send(sock, control->nonce.data,
control->nonce.len) != control->nonce.len){
goto loser;
}
/* Save connection info */
if (CMT_AddDataConnection(control, sock, reply.connID)
!= CMTSuccess) {
goto loser;
}
*connectionID = reply.connID;
rv = CMT_SetPrivate(control, reply.connID, &priv->priv);
if (rv != CMTSuccess)
goto loser;
return CMTSuccess;
}
loser:
if (priv) {
free(priv);
}
*result = reply.result;
return CMTFailure;
}
CMTStatus CMT_PKCS7DecoderUpdate(PCMT_CONTROL control, CMUint32 connectionID, const char * buf, CMUint32 len)
{
CMUint32 sent;
CMTP7Private *priv;
unsigned long nbytes;
char read_buf[128];
CMTSocket sock, ctrlsock, selSock, sockArr[2];
/* Do some parameter checking */
if (!control || !buf) {
goto loser;
}
/* Get the data socket */
if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) {
goto loser;
}
priv = (CMTP7Private *)CMT_GetPrivate(control, connectionID);
if (priv == NULL)
goto loser;
/* Write the data to the socket */
sent = CMT_WriteThisMany(control, sock, (void*)buf, len);
if (sent != len) {
goto loser;
}
ctrlsock = control->sock;
sockArr[0] = ctrlsock;
sockArr[1] = sock;
while ((selSock = control->sockFuncs.select(sockArr,2,1)))
{
if (selSock == ctrlsock) {
CMT_ProcessEvent(control);
} else {
nbytes = control->sockFuncs.recv(sock, read_buf, sizeof(read_buf));
if (nbytes == -1) {
goto loser;
}
if (nbytes == 0) {
break;
}
priv->cb(priv->cb_arg, read_buf, nbytes);
}
}
return CMTSuccess;
loser:
return CMTFailure;
}
CMTStatus CMT_PKCS7DecoderFinish(PCMT_CONTROL control, CMUint32 connectionID,
CMUint32 * resourceID)
{
CMTP7Private *priv;
long nbytes;
char buf[128];
CMTSocket sock, ctrlsock, selSock, sockArr[2];
/* Do some parameter checking */
if (!control) {
goto loser;
}
priv = (CMTP7Private *)CMT_GetPrivate(control, connectionID);
if (priv == NULL)
goto loser;
if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) {
goto loser;
}
ctrlsock = control->sock;
/* drain socket before we close it */
control->sockFuncs.shutdown(sock);
sockArr[0] = sock;
sockArr[1] = ctrlsock;
/* Let's see if doing a poll first gets rid of a weird bug where we
* lock up the client.
*/
#ifndef XP_MAC
if (control->sockFuncs.select(sockArr,2,1) != NULL)
#endif
{
while (1) {
selSock = control->sockFuncs.select(sockArr,2,0);
if (selSock == ctrlsock) {
CMT_ProcessEvent(control);
} else if (selSock == sock) {
nbytes = control->sockFuncs.recv(sock, buf, sizeof(buf));
if (nbytes < 0) {
goto loser;
} else if (nbytes == 0) {
break;
}
priv->cb(priv->cb_arg, buf, nbytes);
}
}
}
if (CMT_CloseDataConnection(control, connectionID) == CMTFailure) {
goto loser;
}
/* Get the PKCS7 content info */
if (CMT_GetRIDAttribute(control, connectionID, SSM_FID_P7CONN_CONTENT_INFO,
resourceID) == CMTFailure) {
goto loser;
}
return CMTSuccess;
loser:
if (control) {
CMT_CloseDataConnection(control, connectionID);
}
return CMTFailure;
}
CMTStatus CMT_PKCS7DestroyContentInfo(PCMT_CONTROL control, CMUint32 resourceID)
{
if (!control) {
goto loser;
}
/* Delete the resource */
if (CMT_DestroyResource(control, resourceID, SSM_FID_P7CONN_CONTENT_INFO) == CMTFailure) {
goto loser;
}
return CMTSuccess;
loser:
return CMTFailure;
}
CMTStatus CMT_PKCS7VerifyDetachedSignature(PCMT_CONTROL control, CMUint32 resourceID, CMUint32 certUsage, CMUint32 hashAlgID, CMUint32 keepCerts, CMTItem* digest, CMInt32 * result)
{
CMTItem message;
VerifyDetachedSigRequest request;
SingleNumMessage reply;
/* Do some parameter checking */
if (!control || !digest || !result) {
goto loser;
}
/* Set the request */
request.pkcs7ContentID = resourceID;
request.certUsage = certUsage;
request.hashAlgID = hashAlgID;
request.keepCert = (CMBool) keepCerts;
request.hash = *digest;
/* Encode the request */
if (CMT_EncodeMessage(VerifyDetachedSigRequestTemplate, &message, &request) != CMTSuccess) {
goto loser;
}
/* Set the message request type */
message.type = SSM_REQUEST_MESSAGE | SSM_OBJECT_SIGNING | SSM_VERIFY_DETACHED_SIG;
/* Send the message */
if (CMT_SendMessage(control, &message) == CMTFailure) {
goto loser;
}
/* Validate the message reply type */
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_OBJECT_SIGNING |SSM_VERIFY_DETACHED_SIG)) {
goto loser;
}
/* Decode the reply */
if (CMT_DecodeMessage(SingleNumMessageTemplate, &reply, &message) != CMTSuccess) {
goto loser;
}
*result = reply.value;
return CMTSuccess;
loser:
*result = reply.value;
return CMTFailure;
}
CMTStatus CMT_PKCS7VerifySignature(PCMT_CONTROL control, CMUint32 pubKeyAlgID,
CMTItem *pubKeyParams, CMTItem *signerPubKey,
CMTItem *computedHash, CMTItem *signature,
CMInt32 *result)
{
return CMTFailure;
}
CMTStatus CMT_CreateSigned(PCMT_CONTROL control, CMUint32 scertRID,
CMUint32 ecertRID, CMUint32 dig_alg,
CMTItem *digest, CMUint32 *ciRID, CMInt32 *errCode)
{
CMTItem message;
CreateSignedRequest request;
CreateContentInfoReply reply;
/* Do some parameter checking */
if (!control || !scertRID || !ecertRID || !digest || !ciRID) {
goto loser;
}
/* Set the request */
request.scertRID = scertRID;
request.ecertRID = ecertRID;
request.dig_alg = dig_alg;
request.digest = *digest;
/* Encode the request */
if (CMT_EncodeMessage(CreateSignedRequestTemplate, &message, &request) != CMTSuccess) {
goto loser;
}
/* Set the message request type */
message.type = SSM_REQUEST_MESSAGE | SSM_OBJECT_SIGNING | SSM_CREATE_SIGNED;
/* Send the message */
if (CMT_SendMessage(control, &message) == CMTFailure) {
goto loser;
}
/* Validate the message reply type */
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_OBJECT_SIGNING | SSM_CREATE_SIGNED)) {
goto loser;
}
/* Decode the reply */
if (CMT_DecodeMessage(CreateContentInfoReplyTemplate, &reply, &message) != CMTSuccess) {
goto loser;
}
*ciRID = reply.ciRID;
if (reply.result == 0) {
return CMTSuccess;
}
loser:
if (CMT_DecodeMessage(CreateContentInfoReplyTemplate, &reply, &message) == CMTSuccess) {
*errCode = reply.errorCode;
} else {
*errCode = 0;
}
return CMTFailure;
}
CMTStatus CMT_CreateEncrypted(PCMT_CONTROL control, CMUint32 scertRID,
CMUint32 *rcertRIDs, CMUint32 *ciRID)
{
CMTItem message;
CMInt32 nrcerts;
CreateEncryptedRequest request;
CreateContentInfoReply reply;
/* Do some parameter checking */
if (!control || !scertRID || !rcertRIDs || !ciRID) {
goto loser;
}
/* Calculate the number of certs */
for (nrcerts =0; rcertRIDs[nrcerts] != 0; nrcerts++) {
/* Nothing */
;
}
/* Set up the request */
request.scertRID = scertRID;
request.nrcerts = nrcerts;
request.rcertRIDs = (long *) rcertRIDs;
/* Encode the request */
if (CMT_EncodeMessage(CreateEncryptedRequestTemplate, &message, &request) != CMTSuccess) {
goto loser;
}
/* Set the message request type */
message.type = SSM_REQUEST_MESSAGE | SSM_OBJECT_SIGNING | SSM_CREATE_ENCRYPTED;
/* Send the message */
if (CMT_SendMessage(control, &message) == CMTFailure) {
goto loser;
}
/* Validate the message response type */
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_OBJECT_SIGNING | SSM_CREATE_ENCRYPTED)) {
goto loser;
}
/* Decode the reply */
if (CMT_DecodeMessage(CreateContentInfoReplyTemplate, &reply, &message) != CMTSuccess) {
goto loser;
}
*ciRID = reply.ciRID;
if (reply.result == 0) {
return CMTSuccess;
}
loser:
return CMTFailure;
}
CMTStatus CMT_PKCS7EncoderStart(PCMT_CONTROL control, CMUint32 ciRID,
CMUint32 *connectionID, CMTP7ContentCallback cb,
void *cb_arg)
{
CMTItem message;
CMTStatus rv;
CMTP7Private *priv;
PKCS7DataConnectionRequest request;
DataConnectionReply reply;
/* Check passed in parameters */
if (!control || !ciRID) {
goto loser;
}
/* Set up the request */
request.resID = ciRID;
request.clientContext.len = 0;
request.clientContext.data = NULL;
/* Encode the request */
if (CMT_EncodeMessage(PKCS7DataConnectionRequestTemplate, &message, &request) != CMTSuccess) {
goto loser;
}
/* Set the message request type */
message.type = SSM_REQUEST_MESSAGE | SSM_DATA_CONNECTION | SSM_PKCS7ENCODE_STREAM;
/* Send the message */
if (CMT_SendMessage(control, &message) == CMTFailure) {
goto loser;
}
/* Validate the message reply type */
if (message.type != (SSM_REPLY_OK_MESSAGE | SSM_DATA_CONNECTION | SSM_PKCS7ENCODE_STREAM)) {
goto loser;
}
/* Decode the reply */
if (CMT_DecodeMessage(DataConnectionReplyTemplate, &reply, &message) != CMTSuccess) {
goto loser;
}
/* Success */
if (reply.result == 0) {
CMTSocket sock;
priv = (CMTP7Private *)malloc(sizeof(CMTP7Private));
if (priv == NULL)
goto loser;
priv->priv.dest = (CMTReclaimFunc) free;
priv->cb = cb;
priv->cb_arg = cb_arg;
sock = control->sockFuncs.socket(0);
if (sock == NULL) {
goto loser;
}
if (control->sockFuncs.connect(sock, (short)reply.port,
NULL) != CMTSuccess) {
goto loser;
}
if (control->sockFuncs.send(sock, control->nonce.data,
control->nonce.len) != control->nonce.len) {
goto loser;
}
/* Save connection info */
if (CMT_AddDataConnection(control, sock, reply.connID)
!= CMTSuccess) {
goto loser;
}
*connectionID = reply.connID;
rv = CMT_SetPrivate(control, reply.connID, &priv->priv);
if (rv != CMTSuccess)
goto loser;
return CMTSuccess;
}
loser:
return CMTFailure;
}
CMTStatus CMT_PKCS7EncoderUpdate(PCMT_CONTROL control, CMUint32 connectionID,
const char *buf, CMUint32 len)
{
CMUint32 sent;
CMTP7Private *priv;
unsigned long nbytes;
char read_buf[128];
CMTSocket sock, ctrlsock, sockArr[2], selSock;
/* Do some parameter checking */
if (!control || !connectionID || !buf) {
goto loser;
}
/* Get the data socket */
if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) {
goto loser;
}
priv = (CMTP7Private *)CMT_GetPrivate(control, connectionID);
if (priv == NULL)
goto loser;
/* Write the data to the socket */
sent = CMT_WriteThisMany(control, sock, (void*)buf, len);
if (sent != len) {
goto loser;
}
ctrlsock = control->sock;
sockArr[0] = ctrlsock;
sockArr[1] = sock;
while ((selSock = control->sockFuncs.select(sockArr, 2, 1)) != NULL)
{
if (selSock == ctrlsock) {
CMT_ProcessEvent(control);
} else {
nbytes = control->sockFuncs.recv(sock, read_buf, sizeof(read_buf));
if (nbytes == -1) {
goto loser;
} else if (nbytes == 0) {
break;
} else {
priv->cb(priv->cb_arg, read_buf, nbytes);
}
}
}
return CMTSuccess;
loser:
return CMTFailure;
}
CMTStatus CMT_PKCS7EncoderFinish(PCMT_CONTROL control, CMUint32 connectionID)
{
CMTP7Private *priv;
unsigned long nbytes;
char buf[128];
CMTSocket sock, ctrlsock, sockArr[2], selSock;
/* Do some parameter checking */
if (!control) {
goto loser;
}
priv = (CMTP7Private *)CMT_GetPrivate(control, connectionID);
if (priv == NULL)
goto loser;
if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) {
goto loser;
}
ctrlsock = control->sock;
sockArr[0] = ctrlsock;
sockArr[1] = sock;
control->sockFuncs.shutdown(sock);
while (1) {
selSock = control->sockFuncs.select(sockArr, 2, 0);
if (selSock == ctrlsock) {
CMT_ProcessEvent(control);
} else if (selSock == sock) {
nbytes = control->sockFuncs.recv(sock, buf, sizeof(buf));
if (nbytes < 0) {
goto loser;
} else if (nbytes == 0) {
break;
} else {
priv->cb(priv->cb_arg, buf, nbytes);
}
}
}
if (CMT_CloseDataConnection(control, connectionID) == CMTFailure) {
goto loser;
}
return CMTSuccess;
loser:
if (control) {
CMT_CloseDataConnection(control, connectionID);
}
return CMTFailure;
}