зеркало из https://github.com/mozilla/gecko-dev.git
Add a file that can pretty print DER blobs.
This commit is contained in:
Родитель
4fb22b1f43
Коммит
10b8991563
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "prio.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
#include "seccomon.h"
|
||||
#include "secerr.h"
|
||||
#include "secder.h"
|
||||
#include "secoid.h"
|
||||
#include "prerror.h"
|
||||
#include "secasn1.h"
|
||||
#include "serv.h"
|
||||
|
||||
#define RIGHT_MARGIN 24
|
||||
/*#define RAW_BYTES 1 */
|
||||
|
||||
static int prettyColumn = 0;
|
||||
|
||||
static int
|
||||
getInteger256(unsigned char *data, unsigned int nb)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (nb) {
|
||||
case 1:
|
||||
val = data[0];
|
||||
break;
|
||||
case 2:
|
||||
val = (data[0] << 8) | data[1];
|
||||
break;
|
||||
case 3:
|
||||
val = (data[0] << 16) | (data[1] << 8) | data[2];
|
||||
break;
|
||||
case 4:
|
||||
val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
break;
|
||||
default:
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyNewline(PRFileDesc *out)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (prettyColumn != -1) {
|
||||
rv = PR_Write(out, "\n",1);
|
||||
prettyColumn = -1;
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PRETTY_INDENT " "
|
||||
|
||||
static int
|
||||
prettyIndent(PRFileDesc *out, unsigned level)
|
||||
{
|
||||
unsigned int i;
|
||||
int rv;
|
||||
|
||||
if (prettyColumn == -1) {
|
||||
prettyColumn = level;
|
||||
for (i = 0; i < level; i++) {
|
||||
rv = PR_Write(out, PRETTY_INDENT, PL_strlen(PRETTY_INDENT));
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintByte(PRFileDesc *out, unsigned char item, unsigned int level)
|
||||
{
|
||||
int rv;
|
||||
char *outdata;
|
||||
|
||||
rv = prettyIndent(out, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
outdata = PR_smprintf("%02x ", item);
|
||||
rv = PR_Write(out, outdata, PL_strlen(outdata));
|
||||
PR_Free(outdata);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
prettyColumn++;
|
||||
if (prettyColumn >= RIGHT_MARGIN) {
|
||||
return prettyNewline(out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintLeaf(PRFileDesc *out, unsigned char *data,
|
||||
unsigned int len, unsigned int lv)
|
||||
{
|
||||
unsigned int i;
|
||||
int rv;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
rv = prettyPrintByte(out, *data++, lv);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
return prettyNewline(out);
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintStringStart(PRFileDesc *out, unsigned char *str,
|
||||
unsigned int len, unsigned int level)
|
||||
{
|
||||
#define BUF_SIZE 100
|
||||
unsigned char staticBuf[BUF_SIZE];
|
||||
unsigned char *buf, *dynamicBuf = NULL;
|
||||
int rv;
|
||||
|
||||
if (len >= BUF_SIZE) {
|
||||
//len = BUF_SIZE - 1;
|
||||
buf = dynamicBuf = SSM_NEW_ARRAY(char, len+1);
|
||||
} else {
|
||||
buf = staticBuf;
|
||||
}
|
||||
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0)
|
||||
goto loser;
|
||||
|
||||
rv = prettyIndent(out, level);
|
||||
if (rv < 0)
|
||||
goto loser;
|
||||
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\000';
|
||||
|
||||
rv = PR_Write(out, buf, len);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
goto loser;
|
||||
}
|
||||
|
||||
return 0;
|
||||
loser:
|
||||
PR_FREEIF(dynamicBuf);
|
||||
return rv;
|
||||
#undef BUF_SIZE
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintString(PRFileDesc *out, unsigned char *str,
|
||||
unsigned int len, unsigned int level, PRBool raw)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = prettyPrintStringStart(out, str, len, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (raw) {
|
||||
rv = prettyPrintLeaf(out, str, len, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pretty_PrintTime(PRFileDesc *out, int64 time, char *m, int level)
|
||||
{
|
||||
PRExplodedTime printableTime;
|
||||
char *timeString;
|
||||
char *newmessage;
|
||||
|
||||
/* Convert to local time */
|
||||
PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
|
||||
|
||||
timeString = PORT_Alloc(100);
|
||||
if (timeString == NULL)
|
||||
return;
|
||||
|
||||
if (m != NULL) {
|
||||
/* SECU_Indent(out, level);*/
|
||||
prettyIndent(out, level);
|
||||
newmessage = PR_smprintf("%s: ", m);
|
||||
PR_Write(out, newmessage, PL_strlen(newmessage));
|
||||
PR_Free(newmessage);
|
||||
}
|
||||
|
||||
PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime);
|
||||
PR_Write(out, timeString, PL_strlen(timeString));
|
||||
|
||||
if (m != NULL)
|
||||
PR_Write(out, "\n", 1);
|
||||
|
||||
PR_Free(timeString);
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintObjectID(PRFileDesc *out, unsigned char *data,
|
||||
unsigned int len, unsigned int level, PRBool raw)
|
||||
{
|
||||
SECOidData *oiddata;
|
||||
SECItem oiditem;
|
||||
unsigned int i;
|
||||
unsigned long val;
|
||||
int rv;
|
||||
char buf[300];
|
||||
|
||||
|
||||
/*
|
||||
* First print the Object Id in numeric format
|
||||
*/
|
||||
|
||||
rv = prettyIndent(out, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
val = data[0];
|
||||
i = val % 40;
|
||||
val = val / 40;
|
||||
PR_snprintf(buf, 300, "%lu %u ", val, i);
|
||||
rv = PR_Write(out,buf,PL_strlen(buf));
|
||||
if (rv < 0) {
|
||||
PORT_SetError(SEC_ERROR_IO);
|
||||
return rv;
|
||||
}
|
||||
|
||||
val = 0;
|
||||
for (i = 1; i < len; ++i) {
|
||||
unsigned long j;
|
||||
|
||||
j = data[i];
|
||||
val = (val << 7) | (j & 0x7f);
|
||||
if (j & 0x80)
|
||||
continue;
|
||||
PR_snprintf(buf, 300, "%lu ", val);
|
||||
rv = PR_Write(out, buf, PL_strlen(buf));
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
val = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try to look it up and print a symbolic version.
|
||||
*/
|
||||
oiditem.data = data;
|
||||
oiditem.len = len;
|
||||
oiddata = SECOID_FindOID(&oiditem);
|
||||
if (oiddata != NULL) {
|
||||
i = PL_strlen(oiddata->desc);
|
||||
if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) {
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = prettyIndent(out, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
PR_snprintf(buf, 300, "(%s)", oiddata->desc);
|
||||
rv = PR_Write(out, buf, PL_strlen(buf));
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, on a new line, print the raw bytes (if requested).
|
||||
*/
|
||||
if (raw) {
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
rv = prettyPrintByte(out, *data++, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return prettyNewline(out);
|
||||
}
|
||||
|
||||
static char *prettyTagType [32] = {
|
||||
"End of Contents",
|
||||
"Boolean",
|
||||
"Integer",
|
||||
"Bit String",
|
||||
"Octet String",
|
||||
"NULL",
|
||||
"Object Identifier",
|
||||
"0x07",
|
||||
"0x08",
|
||||
"0x09",
|
||||
"Enumerated",
|
||||
"0x0B",
|
||||
"UTF8 String",
|
||||
"0x0D",
|
||||
"0x0E",
|
||||
"0x0F",
|
||||
"Sequence",
|
||||
"Set",
|
||||
"0x12",
|
||||
"Printable String",
|
||||
"T61 String",
|
||||
"0x15",
|
||||
"IA5 String",
|
||||
"UTC Time",
|
||||
"Generalized Time",
|
||||
"0x19",
|
||||
"Visible String",
|
||||
"0x1B",
|
||||
"Universal String",
|
||||
"0x1D",
|
||||
"BMP String",
|
||||
"High-Tag-Number"
|
||||
};
|
||||
|
||||
static int
|
||||
prettyPrintTime(PRFileDesc *out, unsigned char *str,
|
||||
unsigned int len, unsigned int level, PRBool raw, PRBool utc)
|
||||
{
|
||||
SECItem time_item;
|
||||
int rv;
|
||||
SECStatus srv;
|
||||
int64 time;
|
||||
|
||||
rv = prettyPrintStringStart(out, str, len, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
time_item.data = str;
|
||||
time_item.len = len;
|
||||
|
||||
rv = PR_Write(out, " (", 2);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (utc) {
|
||||
srv = DER_UTCTimeToTime(&time, &time_item);
|
||||
if (srv == SECSuccess)
|
||||
pretty_PrintTime(out, time, NULL, 0);
|
||||
} else{
|
||||
srv = DER_GeneralizedTimeToTime(&time, &time_item);
|
||||
if (srv == SECSuccess)
|
||||
pretty_PrintTime(out, time, NULL, 0);
|
||||
}
|
||||
|
||||
rv = PR_Write(out, ")", 1);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (raw) {
|
||||
rv = prettyPrintLeaf(out, str, len, level);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintTag(PRFileDesc *out, unsigned char *src, unsigned char *end,
|
||||
unsigned char *codep, unsigned int level, PRBool raw)
|
||||
{
|
||||
int rv;
|
||||
unsigned char code, tagnum;
|
||||
char *msg;
|
||||
|
||||
if (src >= end) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
code = *src;
|
||||
tagnum = code & SEC_ASN1_TAGNUM_MASK;
|
||||
|
||||
/*
|
||||
* NOTE: This code does not (yet) handle the high-tag-number form!
|
||||
*/
|
||||
if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (raw)
|
||||
rv = prettyPrintByte(out, code, level);
|
||||
else
|
||||
rv = prettyIndent(out, level);
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (code & SEC_ASN1_CONSTRUCTED) {
|
||||
rv = PR_Write(out, "C-",2);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
switch (code & SEC_ASN1_CLASS_MASK) {
|
||||
case SEC_ASN1_UNIVERSAL:
|
||||
rv = PR_Write(out, prettyTagType[tagnum],
|
||||
PL_strlen(prettyTagType[tagnum]));
|
||||
break;
|
||||
case SEC_ASN1_APPLICATION:
|
||||
msg = PR_smprintf("Application: %d ", tagnum);
|
||||
rv = PR_Write(out,msg, PL_strlen(msg));
|
||||
PR_Free(msg);
|
||||
break;
|
||||
case SEC_ASN1_CONTEXT_SPECIFIC:
|
||||
msg = PR_smprintf("[%d] ", tagnum);
|
||||
rv = PR_Write(out, msg, PL_strlen(msg));
|
||||
PR_Free(msg);
|
||||
break;
|
||||
case SEC_ASN1_PRIVATE:
|
||||
msg = PR_smprintf("Private: %d ", tagnum);
|
||||
rv = PR_Write(out, msg, PL_strlen(msg));
|
||||
break;
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*codep = code;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintLength(PRFileDesc *out, unsigned char *data, unsigned char *end,
|
||||
int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw)
|
||||
{
|
||||
unsigned char lbyte;
|
||||
int lenLen;
|
||||
int rv;
|
||||
|
||||
if (data >= end) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = PR_Write(out, " ",1);
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*indefinitep = PR_FALSE;
|
||||
|
||||
lbyte = *data++;
|
||||
if (lbyte >= 0x80) {
|
||||
/* Multibyte length */
|
||||
unsigned nb = (unsigned) (lbyte & 0x7f);
|
||||
if (nb > 4) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
if (nb > 0) {
|
||||
int il;
|
||||
|
||||
if ((data + nb) > end) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
il = getInteger256(data, nb);
|
||||
if (il < 0) return -1;
|
||||
*lenp = (unsigned) il;
|
||||
} else {
|
||||
*lenp = 0;
|
||||
*indefinitep = PR_TRUE;
|
||||
}
|
||||
lenLen = nb + 1;
|
||||
if (raw) {
|
||||
unsigned int i;
|
||||
|
||||
rv = prettyPrintByte(out, lbyte, lv);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
for (i = 0; i < nb; i++) {
|
||||
rv = prettyPrintByte(out, data[i], lv);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*lenp = lbyte;
|
||||
lenLen = 1;
|
||||
if (raw) {
|
||||
rv = prettyPrintByte(out, lbyte, lv);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (*indefinitep) {
|
||||
rv = PR_Write(out, "(indefinite)\n", PL_strlen("(indefinite)\n"));
|
||||
} else {
|
||||
char *msg;
|
||||
|
||||
msg= PR_smprintf("(%d)\n", *lenp);
|
||||
rv = PR_Write(out, msg, PL_strlen(msg));
|
||||
}
|
||||
if (rv < 0) {
|
||||
PR_SetError(SEC_ERROR_IO,0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
prettyColumn = -1;
|
||||
return lenLen;
|
||||
}
|
||||
|
||||
static int
|
||||
prettyPrintItem(PRFileDesc *out, unsigned char *data, unsigned char *end,
|
||||
unsigned int lv, PRBool raw)
|
||||
{
|
||||
int slen;
|
||||
int lenLen;
|
||||
unsigned char *orig = data;
|
||||
int rv;
|
||||
|
||||
while (data < end) {
|
||||
unsigned char code;
|
||||
PRBool indefinite;
|
||||
|
||||
slen = prettyPrintTag(out, data, end, &code, lv, raw);
|
||||
if (slen < 0)
|
||||
return slen;
|
||||
data += slen;
|
||||
|
||||
lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
|
||||
if (lenLen < 0)
|
||||
return lenLen;
|
||||
data += lenLen;
|
||||
|
||||
/*
|
||||
* Just quit now if slen more bytes puts us off the end.
|
||||
*/
|
||||
if ((data + slen) > end) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (code & SEC_ASN1_CONSTRUCTED) {
|
||||
if (slen > 0 || indefinite) {
|
||||
slen = prettyPrintItem(out, data,
|
||||
slen == 0 ? end : data + slen,
|
||||
lv+1, raw);
|
||||
if (slen < 0)
|
||||
return slen;
|
||||
data += slen;
|
||||
}
|
||||
} else if (code == 0) {
|
||||
if (slen != 0 || lenLen != 1) {
|
||||
PR_SetError(SEC_ERROR_BAD_DER,0);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
switch (code) {
|
||||
case SEC_ASN1_PRINTABLE_STRING:
|
||||
case SEC_ASN1_IA5_STRING:
|
||||
case SEC_ASN1_VISIBLE_STRING:
|
||||
case SEC_ASN1_T61_STRING:
|
||||
case SEC_ASN1_UTF8_STRING:
|
||||
rv = prettyPrintString(out, data, slen, lv+1, raw);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case SEC_ASN1_UTC_TIME:
|
||||
rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case SEC_ASN1_GENERALIZED_TIME:
|
||||
rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case SEC_ASN1_OBJECT_ID:
|
||||
rv = prettyPrintObjectID(out, data, slen, lv+1, raw);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case SEC_ASN1_OCTET_STRING:
|
||||
//rv = prettyPrintOctetString(out,data,slen,lv+1);
|
||||
rv = prettyPrintItem(out,data,data+slen,lv+1, raw);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
case SEC_ASN1_BOOLEAN: /* could do nicer job */
|
||||
case SEC_ASN1_INTEGER: /* could do nicer job */
|
||||
case SEC_ASN1_BIT_STRING: /* could do nicer job */
|
||||
case SEC_ASN1_NULL:
|
||||
case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */
|
||||
case SEC_ASN1_UNIVERSAL_STRING:
|
||||
case SEC_ASN1_BMP_STRING:
|
||||
default:
|
||||
rv = prettyPrintLeaf(out, data, slen, lv+1);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
break;
|
||||
}
|
||||
data += slen;
|
||||
}
|
||||
}
|
||||
|
||||
rv = prettyNewline(out);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
return data - orig;
|
||||
}
|
||||
|
||||
SSMStatus
|
||||
SSM_PrettyPrintDER(PRFileDesc *out, SECItem *it, PRBool raw)
|
||||
{
|
||||
int rv;
|
||||
|
||||
prettyColumn = -1;
|
||||
|
||||
rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
|
||||
if (rv < 0)
|
||||
return SSM_FAILURE;
|
||||
return SSM_SUCCESS;
|
||||
}
|
Загрузка…
Ссылка в новой задаче