/* * 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 #include "padding.h" #ifdef _KERNEL #include #else #include #include #endif /* * To create a block type "02" encryption block for RSA PKCS encryption * process. * * This is EME-PKCS1-v1_5 encoding as described in RSA PKCS#1. * * The RSA PKCS Padding before encryption is in the following format: * +----+----+--------------------+----+-----------------------------+ * |0x00|0x02| 8 bytes or more RN |0x00| DATA | * +----+----+--------------------+----+-----------------------------+ * * * To create a block type "01" block for RSA PKCS signature process. * * This EMSA-PKCS1-1_5 encoding as decribed in RSA PKCS#1. * * The RSA PKCS Padding before Signing is in the following format: * +----+----+----------------------+----+-----------------------------+ * |0x00|0x01| 8 bytes of more 0xFF |0x00| DATA | * +----+----+----------------------+----+-----------------------------+ * */ int pkcs1_encode(int method, uint8_t *databuf, size_t datalen, uint8_t *padbuf, size_t padbuflen) { size_t padlen; int rv; padlen = padbuflen - datalen; if (padlen < MIN_PKCS1_PADLEN) { return (CKR_DATA_LEN_RANGE); } rv = 0; padbuf[0] = 0x00; padbuf[1] = (method == PKCS1_ENCRYPT) ? 0x02 : 0x01; if (method == PKCS1_ENCRYPT) { #ifdef _KERNEL rv = knzero_random_generator(padbuf + 2, padlen - 3); #else rv = (pkcs11_get_nzero_urandom(padbuf + 2, padlen - 3) < 0) ? CKR_DEVICE_ERROR : 0; #endif } else if (method == PKCS1_SIGN) { #ifdef _KERNEL kmemset(padbuf + 2, 0xFF, padlen - 3); #else (void) memset(padbuf + 2, 0xFF, padlen - 3); #endif } if (rv != 0) { return (rv); } padbuf[padlen - 1] = 0x00; bcopy(databuf, padbuf + padlen, datalen); return (0); } /* * The RSA PKCS Padding in the following format: * +----+----+-------------------------+----+------------------------+ * |0x00| BT | 8 bytes or more padding |0x00| DATA | * +----+----+-+++++-------------------+----+------------------------+ * where BT is block type: 0x02 for encrypt/decrypt, 0x01 for sign/verify * * '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. */ int pkcs1_decode(int method, uint8_t *padbuf, size_t *plen) { int rv = ((method == PKCS1_DECRYPT) ? CKR_ENCRYPTED_DATA_INVALID : CKR_SIGNATURE_INVALID); int i; /* Check to see if the recovered data is padded is 0x0002 or 0x0001. */ if (padbuf[0] != 0x00 || padbuf[1] != (method == PKCS1_DECRYPT ? 0x02 : 0x01)) { return (rv); } /* Remove all the random bits up to 0x00 (= NULL char) */ for (i = 2; (*plen - i) > 0; i++) { if (padbuf[i] == 0x00) { i++; if (i < MIN_PKCS1_PADLEN) { return (rv); } *plen -= i; return (0); } else if (method == PKCS1_VERIFY && padbuf[i] != 0xFF) { return (rv); } } return (rv); }