pkcs7.c revision 726fad2a65f16c200a03969c29cb5c86c2d427db
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* This file contains padding helper routines common to
* the PKCS11 soft token code and the kernel crypto code.
*/
#include <sys/types.h>
#include "padding.h"
#ifdef _KERNEL
#include <sys/param.h>
#else
#include <strings.h>
#include <cryptoutil.h>
#endif
/*
* This is padding as decribed in Section 10.3 of RSA PKCS#7.
*
* The RSA PKCS Padding is in the following format:
* +-----------------------------+----+-------------+
* | DATA |0x0k|0x0k|...|0x0k|
* +-----------------------------+----+----+---+----+
* where 0x0k is if data_len mod multiple = multiple - k
* and multiple < 256 and 1 <= k <= multiple
*
* If databuf is non NULL, padbuf must be large enough
* to contain both databuf and the padding. databuf and
* padbuf may be the same buffer.
* databuf:
* +-----------------------------+
* | DATA |
* +-----------------------------+
* datalen
* padbuf:
* +-----------------------------+----+-------------+
* | DATA |0x0k|0x0k|...|0x0k|
* +-----------------------------+----+----+---+----+
* datalen padbuflen
*
* If databuf is NULL, padbuf only needs to be large
* enough for the padding, and datalen must still be
* provided to compute the padding value:
* padbuf:
* +----+-------------+
* |0x0k|0x0k|...|0x0k|
* +----+----+---+----+
* datalen padbuflen
*/
int
pkcs7_encode(uint8_t *databuf, size_t datalen, uint8_t *padbuf,
size_t padbuflen, uint8_t multiple)
{
size_t padlen;
padlen = multiple - (datalen % multiple);
if (databuf == NULL)
datalen = 0;
if (padlen > padbuflen - datalen) {
return (CKR_DATA_LEN_RANGE);
}
bcopy(databuf, padbuf, datalen);
(void) memset(padbuf + datalen, padlen & 0xff, padlen);
return (0);
}
/*
* 'padbuf' points to the recovered message. Strip off the padding and
* validate it as much as possible. 'plen' is changed to hold the actual
* data length. 'padbuf' is unchanged.
*/
int
pkcs7_decode(uint8_t *padbuf, size_t *plen)
{
int i;
size_t padlen;
/* Recover the padding value, even if padbuf has trailing nulls */
while (*plen > 0 && (padlen = padbuf[*plen - 1]) == 0)
(*plen)--;
/* Must have non-zero padding */
if (padlen == 0)
return (CKR_ENCRYPTED_DATA_INVALID);
/* Count back from all padding bytes; lint tag is for *plen-1-i >= 0 */
/* LINTED E_SUSPICIOUS_COMPARISON */
for (i = 0; i < padlen && (*plen - 1 - i) >= 0; i++) {
if (padbuf[*plen - 1 - i] != (padlen & 0xff))
return (CKR_ENCRYPTED_DATA_INVALID);
}
*plen -= i;
return (0);
}