p7local.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,432 行 · 第 1/3 页
C
1,432 行
/* * hardware encryption does not like small decryption sizes here, so we * allow both blocking and padding. */ bsize = obj->block_size; padsize = obj->pad_size; /* * When no blocking or padding work to do, we can simply call the * cipher function and we are done. */ if (bsize == 0) { return (* obj->doit) (obj->cx, output, output_len_p, max_output_len, input, input_len); } pcount = obj->pending_count; pbuf = obj->pending_buf; output_len = 0; if (pcount) { /* * Try to fill in an entire block, starting with the bytes * we already have saved away. */ while (input_len && pcount < bsize) { pbuf[pcount++] = *input++; input_len--; } /* * If we have at most a whole block and this is not our last call, * then we are done for now. (We do not try to decrypt a lone * single block because we cannot interpret the padding bytes * until we know we are handling the very last block of all input.) */ if (input_len == 0 && !final) { obj->pending_count = pcount; if (output_len_p) *output_len_p = 0; return SECSuccess; } /* * Given the logic above, we expect to have a full block by now. * If we do not, there is something wrong, either with our own * logic or with (length of) the data given to us. */ PORT_Assert ((padsize == 0) || (pcount % padsize) == 0); if ((padsize != 0) && (pcount % padsize) != 0) { PORT_Assert (final); PORT_SetError (SEC_ERROR_BAD_DATA); return SECFailure; } /* * Decrypt the block. */ rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len, pbuf, pcount); if (rv != SECSuccess) return rv; /* * For now anyway, all of our ciphers have the same number of * bytes of output as they do input. If this ever becomes untrue, * then sec_PKCS7DecryptLength needs to be made smarter! */ PORT_Assert (ofraglen == pcount); /* * Account for the bytes now in output. */ max_output_len -= ofraglen; output_len += ofraglen; output += ofraglen; } /* * If this is our last call, we expect to have an exact number of * blocks left to be decrypted; we will decrypt them all. * * If not our last call, we always save between 1 and bsize bytes * until next time. (We must do this because we cannot be sure * that none of the decrypted bytes are padding bytes until we * have at least another whole block of data. You cannot tell by * looking -- the data could be anything -- you can only tell by * context, knowing you are looking at the last block.) We could * decrypt a whole block now but it is easier if we just treat it * the same way we treat partial block bytes. */ if (final) { if (padsize) { blocks = input_len / padsize; ifraglen = blocks * padsize; } else ifraglen = input_len; PORT_Assert (ifraglen == input_len); if (ifraglen != input_len) { PORT_SetError (SEC_ERROR_BAD_DATA); return SECFailure; } } else { blocks = (input_len - 1) / bsize; ifraglen = blocks * bsize; PORT_Assert (ifraglen < input_len); pcount = input_len - ifraglen; PORT_Memcpy (pbuf, input + ifraglen, pcount); obj->pending_count = pcount; } if (ifraglen) { rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len, input, ifraglen); if (rv != SECSuccess) return rv; /* * For now anyway, all of our ciphers have the same number of * bytes of output as they do input. If this ever becomes untrue, * then sec_PKCS7DecryptLength needs to be made smarter! */ PORT_Assert (ifraglen == ofraglen); if (ifraglen != ofraglen) { PORT_SetError (SEC_ERROR_BAD_DATA); return SECFailure; } output_len += ofraglen; } else { ofraglen = 0; } /* * If we just did our very last block, "remove" the padding by * adjusting the output length. */ if (final && (padsize != 0)) { unsigned int padlen = *(output + ofraglen - 1); PORT_Assert (padlen > 0 && padlen <= padsize); if (padlen == 0 || padlen > padsize) { PORT_SetError (SEC_ERROR_BAD_DATA); return SECFailure; } output_len -= padlen; } PORT_Assert (output_len_p != NULL || output_len == 0); if (output_len_p != NULL) *output_len_p = output_len; return SECSuccess;}/* * Encrypt a given length of input buffer (starting at "input" and * containing "input_len" bytes), placing the encrypted bytes in * "output" and storing the output length in "*output_len_p". * "obj" is the return value from sec_PKCS7CreateEncryptObject. * When "final" is true, this is the last of the data to be encrypted. * * This is much more complicated than it sounds when the cipher is * a block-type, meaning that the encryption function will only * operate on whole blocks. But our caller is operating stream-wise, * and can pass in any number of bytes. So we need to keep track * of block boundaries. We save excess bytes between calls in "obj". * We also need to add padding bytes at the end. PKCS #7 specifies * that the padding used for a block cipher is a string of bytes, * each of whose value is the same as the length of the padding, * and that all data is padded. (Even data that starts out with * an exact multiple of blocks gets added to it another block, * all of which is padding.) * * XXX I would kind of like to combine this with the function above * which does decryption, since they have a lot in common. But the * tricky parts about padding and filling blocks would be much * harder to read that way, so I left them separate. At least for * now until it is clear that they are right. */ SECStatussec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output, unsigned int *output_len_p, unsigned int max_output_len, const unsigned char *input, unsigned int input_len, PRBool final){ int blocks, bsize, padlen, pcount, padsize; unsigned int max_needed, ifraglen, ofraglen, output_len; unsigned char *pbuf; SECStatus rv; PORT_Assert (obj->encrypt); /* * Check that we have enough room for the output. Our caller should * already handle this; failure is really an internal error (i.e. bug). */ max_needed = sec_PKCS7EncryptLength (obj, input_len, final); PORT_Assert (max_output_len >= max_needed); if (max_output_len < max_needed) { /* PORT_SetError (XXX); */ return SECFailure; } bsize = obj->block_size; padsize = obj->pad_size; /* * When no blocking and padding work to do, we can simply call the * cipher function and we are done. */ if (bsize == 0) { return (* obj->doit) (obj->cx, output, output_len_p, max_output_len, input, input_len); } pcount = obj->pending_count; pbuf = obj->pending_buf; output_len = 0; if (pcount) { /* * Try to fill in an entire block, starting with the bytes * we already have saved away. */ while (input_len && pcount < bsize) { pbuf[pcount++] = *input++; input_len--; } /* * If we do not have a full block and we know we will be * called again, then we are done for now. */ if (pcount < bsize && !final) { obj->pending_count = pcount; if (output_len_p != NULL) *output_len_p = 0; return SECSuccess; } /* * If we have a whole block available, encrypt it. */ if ((padsize == 0) || (pcount % padsize) == 0) { rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len, pbuf, pcount); if (rv != SECSuccess) return rv; /* * For now anyway, all of our ciphers have the same number of * bytes of output as they do input. If this ever becomes untrue, * then sec_PKCS7EncryptLength needs to be made smarter! */ PORT_Assert (ofraglen == pcount); /* * Account for the bytes now in output. */ max_output_len -= ofraglen; output_len += ofraglen; output += ofraglen; pcount = 0; } } if (input_len) { PORT_Assert (pcount == 0); blocks = input_len / bsize; ifraglen = blocks * bsize; if (ifraglen) { rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len, input, ifraglen); if (rv != SECSuccess) return rv; /* * For now anyway, all of our ciphers have the same number of * bytes of output as they do input. If this ever becomes untrue, * then sec_PKCS7EncryptLength needs to be made smarter! */ PORT_Assert (ifraglen == ofraglen); max_output_len -= ofraglen; output_len += ofraglen; output += ofraglen; } pcount = input_len - ifraglen; PORT_Assert (pcount < bsize); if (pcount) PORT_Memcpy (pbuf, input + ifraglen, pcount); } if (final) { padlen = padsize - (pcount % padsize); PORT_Memset (pbuf + pcount, padlen, padlen); rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len, pbuf, pcount+padlen); if (rv != SECSuccess) return rv; /* * For now anyway, all of our ciphers have the same number of * bytes of output as they do input. If this ever becomes untrue, * then sec_PKCS7EncryptLength needs to be made smarter! */ PORT_Assert (ofraglen == (pcount+padlen)); output_len += ofraglen; } else { obj->pending_count = pcount; } PORT_Assert (output_len_p != NULL || output_len == 0); if (output_len_p != NULL) *output_len_p = output_len; return SECSuccess;}/* * End of cipher stuff. * ------------------------------------------------------------------- *//* * ------------------------------------------------------------------- * XXX The following Attribute stuff really belongs elsewhere. * The Attribute type is *not* part of pkcs7 but rather X.501. * But for now, since PKCS7 is the only customer of attributes, * we define them here. Once there is a use outside of PKCS7, * then change the attribute types and functions from internal * to external naming convention, and move them elsewhere! *//* * Look through a set of attributes and find one that matches the * specified object ID. If "only" is true, then make sure that * there is not more than one attribute of the same type. Otherwise, * just return the first one found. (XXX Does anybody really want * that first-found behavior? It was like that when I found it...) */SEC_PKCS7Attribute *sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag, PRBool only){ SECOidData *oid; SEC_PKCS7Attribute *attr1, *attr2; if (attrs == NULL) return NULL; oid = SECOID_FindOIDByTag(oidtag); if (oid == NULL) return NULL; while ((attr1 = *attrs++) != NULL) { if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data, oid->oid.data, oid->oid.len) == 0) break; } if (attr1 == NULL) return NULL; if (!only) return attr1; while ((attr2 = *attrs++) != NULL) { if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data, oid->oid.data, oid->oid.len) == 0) break; } if (attr2 != NULL) return NULL; return attr1;}/* * Return the single attribute value, doing some sanity checking first: * - Multiple values are *not* expected. * - Empty values are *not* expected. */SECItem *sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr){ SECItem *value; if (attr == NULL) return NULL; value = attr->values[0]; if (value == NULL || value->data == NULL || value->len == 0) return NULL; if (attr->values[1] != NULL) return NULL; return value;}static const SEC_ASN1Template *sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding){ const SEC_ASN1Template *theTemplate; SEC_PKCS7Attribute *attribute; SECOidData *oiddata; PRBool encoded; PORT_Assert (src_or_dest != NULL); if (src_or_dest == NULL) return NULL; attribute = (SEC_PKCS7Attribute*)src_or_dest; if (encoding && attribute->encoded) return SEC_AnyTemplate; oiddata = attribute->typeTag; if (oiddata == NULL) { oiddata = SECOID_FindOID(&attribute->type); attribute->typeTag = oiddata; } if (oiddata == NULL) { encoded = PR_TRUE; theTemplate = SEC_AnyTemplate; } else { switch (oiddata->offset) { default: encoded = PR_TRUE; theTemplate = SEC_AnyTemplate; break; case SEC_OID_PKCS9_EMAIL_ADDRESS: case SEC_OID_RFC1274_MAIL: case SEC_OID_PKCS9_UNSTRUCTURED_NAME: encoded = PR_FALSE; theTemplate = SEC_IA5StringTemplate; break; case SEC_OID_PKCS9_CONTENT_TYPE: encoded = PR_FALSE; theTemplate = SEC_ObjectIDTemplate; break; case SEC_OID_PKCS9_MESSAGE_DIGEST: encoded = PR_FALSE; theTemplate = SEC_OctetStringTemplate; break; case SEC_OID_PKCS9_SIGNING_TIME: encoded = PR_FALSE; theTemplate = SEC_UTCTimeTemplate; break; /* XXX Want other types here, too */ } } if (encoding) { /* * If we are encoding and we think we have an already-encoded value, * then the code which initialized this attribute should have set * the "encoded" property to true (and we would have returned early, * up above). No devastating error, but that code should be fixed. * (It could indicate that the resulting encoded bytes are wrong.) */ PORT_Assert (!encoded); } else { /* * We are decoding; record whether the resulting value is * still encoded or not. */ attribute->encoded = encoded;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?