Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35860093
certdump.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
15 KB
Subscribers
None
certdump.c
View Options
/* certdump.c - Dump a certificate for debugging
* Copyright (C) 2001, 2004 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<errno.h>
#include
<unistd.h>
#include
<time.h>
#include
<assert.h>
#ifdef HAVE_LOCALE_H
#include
<locale.h>
#endif
#ifdef HAVE_LANGINFO_CODESET
#include
<langinfo.h>
#endif
#include
"gpgsm.h"
#include
<gcrypt.h>
#include
<ksba.h>
#include
"keydb.h"
#include
"i18n.h"
struct
dn_array_s
{
char
*
key
;
char
*
value
;
int
multivalued
;
int
done
;
};
/* print the first element of an S-Expression */
void
gpgsm_print_serial
(
FILE
*
fp
,
ksba_const_sexp_t
p
)
{
unsigned
long
n
;
char
*
endp
;
if
(
!
p
)
fputs
(
_
(
"none"
),
fp
);
else
if
(
*
p
!=
'('
)
fputs
(
"[Internal error - not an S-expression]"
,
fp
);
else
{
p
++
;
n
=
strtoul
(
p
,
&
endp
,
10
);
p
=
endp
;
if
(
*
p
!=
':'
)
fputs
(
"[Internal Error - invalid S-expression]"
,
fp
);
else
{
for
(
p
++
;
n
;
n
--
,
p
++
)
fprintf
(
fp
,
"%02X"
,
*
p
);
}
}
}
void
gpgsm_dump_serial
(
ksba_const_sexp_t
p
)
{
unsigned
long
n
;
char
*
endp
;
if
(
!
p
)
log_printf
(
"none"
);
else
if
(
*
p
!=
'('
)
log_printf
(
"ERROR - not an S-expression"
);
else
{
p
++
;
n
=
strtoul
(
p
,
&
endp
,
10
);
p
=
endp
;
if
(
*
p
!=
':'
)
log_printf
(
"ERROR - invalid S-expression"
);
else
{
for
(
p
++
;
n
;
n
--
,
p
++
)
log_printf
(
"%02X"
,
*
p
);
}
}
}
char
*
gpgsm_format_serial
(
ksba_const_sexp_t
p
)
{
unsigned
long
n
;
char
*
endp
;
char
*
buffer
;
int
i
;
if
(
!
p
)
return
NULL
;
if
(
*
p
!=
'('
)
BUG
();
/* Not a valid S-expression. */
p
++
;
n
=
strtoul
(
p
,
&
endp
,
10
);
p
=
endp
;
if
(
*
p
!=
':'
)
BUG
();
/* Not a valid S-expression. */
p
++
;
buffer
=
xtrymalloc
(
n
*
2
+
1
);
if
(
buffer
)
{
for
(
i
=
0
;
n
;
n
--
,
p
++
,
i
+=
2
)
sprintf
(
buffer
+
i
,
"%02X"
,
*
(
unsigned
char
*
)
p
);
buffer
[
i
]
=
0
;
}
return
buffer
;
}
void
gpgsm_print_time
(
FILE
*
fp
,
ksba_isotime_t
t
)
{
if
(
!
t
||
!*
t
)
fputs
(
_
(
"none"
),
fp
);
else
fprintf
(
fp
,
"%.4s-%.2s-%.2s %.2s:%.2s:%s"
,
t
,
t
+
4
,
t
+
6
,
t
+
9
,
t
+
11
,
t
+
13
);
}
void
gpgsm_dump_time
(
ksba_isotime_t
t
)
{
if
(
!
t
||
!*
t
)
log_printf
(
_
(
"[none]"
));
else
log_printf
(
"%.4s-%.2s-%.2s %.2s:%.2s:%s"
,
t
,
t
+
4
,
t
+
6
,
t
+
9
,
t
+
11
,
t
+
13
);
}
void
gpgsm_dump_string
(
const
char
*
string
)
{
if
(
!
string
)
log_printf
(
"[error]"
);
else
{
const
unsigned
char
*
s
;
for
(
s
=
string
;
*
s
;
s
++
)
{
if
(
*
s
<
' '
||
(
*
s
>=
0x7f
&&
*
s
<=
0xa0
))
break
;
}
if
(
!*
s
&&
*
string
!=
'['
)
log_printf
(
"%s"
,
string
);
else
{
log_printf
(
"[ "
);
log_printhex
(
NULL
,
string
,
strlen
(
string
));
log_printf
(
" ]"
);
}
}
}
void
gpgsm_dump_cert
(
const
char
*
text
,
ksba_cert_t
cert
)
{
ksba_sexp_t
sexp
;
unsigned
char
*
p
;
char
*
dn
;
ksba_isotime_t
t
;
log_debug
(
"BEGIN Certificate `%s':
\n
"
,
text
?
text
:
""
);
if
(
cert
)
{
sexp
=
ksba_cert_get_serial
(
cert
);
log_debug
(
" serial: "
);
gpgsm_dump_serial
(
sexp
);
ksba_free
(
sexp
);
log_printf
(
"
\n
"
);
ksba_cert_get_validity
(
cert
,
0
,
t
);
log_debug
(
" notBefore: "
);
gpgsm_dump_time
(
t
);
log_printf
(
"
\n
"
);
ksba_cert_get_validity
(
cert
,
1
,
t
);
log_debug
(
" notAfter: "
);
gpgsm_dump_time
(
t
);
log_printf
(
"
\n
"
);
dn
=
ksba_cert_get_issuer
(
cert
,
0
);
log_debug
(
" issuer: "
);
gpgsm_dump_string
(
dn
);
ksba_free
(
dn
);
log_printf
(
"
\n
"
);
dn
=
ksba_cert_get_subject
(
cert
,
0
);
log_debug
(
" subject: "
);
gpgsm_dump_string
(
dn
);
ksba_free
(
dn
);
log_printf
(
"
\n
"
);
log_debug
(
" hash algo: %s
\n
"
,
ksba_cert_get_digest_algo
(
cert
));
p
=
gpgsm_get_fingerprint_string
(
cert
,
0
);
log_debug
(
" SHA1 Fingerprint: %s
\n
"
,
p
);
xfree
(
p
);
}
log_debug
(
"END Certificate
\n
"
);
}
/* helper for the rfc2253 string parser */
static
const
unsigned
char
*
parse_dn_part
(
struct
dn_array_s
*
array
,
const
unsigned
char
*
string
)
{
static
struct
{
const
char
*
label
;
const
char
*
oid
;
}
label_map
[]
=
{
/* Warning: When adding new labels, make sure that the buffer
below we be allocated large enough. */
{
"EMail"
,
"1.2.840.113549.1.9.1"
},
{
"T"
,
"2.5.4.12"
},
{
"GN"
,
"2.5.4.42"
},
{
"SN"
,
"2.5.4.4"
},
{
"NameDistinguisher"
,
"0.2.262.1.10.7.20"
},
{
"ADDR"
,
"2.5.4.16"
},
{
"BC"
,
"2.5.4.15"
},
{
"D"
,
"2.5.4.13"
},
{
"PostalCode"
,
"2.5.4.17"
},
{
"Pseudo"
,
"2.5.4.65"
},
{
"SerialNumber"
,
"2.5.4.5"
},
{
NULL
,
NULL
}
};
const
unsigned
char
*
s
,
*
s1
;
size_t
n
;
unsigned
char
*
p
;
int
i
;
/* Parse attributeType */
for
(
s
=
string
+
1
;
*
s
&&
*
s
!=
'='
;
s
++
)
;
if
(
!*
s
)
return
NULL
;
/* error */
n
=
s
-
string
;
if
(
!
n
)
return
NULL
;
/* empty key */
/* We need to allocate a few bytes more due to the possible mapping
from the shorter OID to the longer label. */
array
->
key
=
p
=
xtrymalloc
(
n
+
10
);
if
(
!
array
->
key
)
return
NULL
;
memcpy
(
p
,
string
,
n
);
p
[
n
]
=
0
;
trim_trailing_spaces
(
p
);
if
(
digitp
(
p
))
{
for
(
i
=
0
;
label_map
[
i
].
label
;
i
++
)
if
(
!
strcmp
(
p
,
label_map
[
i
].
oid
)
)
{
strcpy
(
p
,
label_map
[
i
].
label
);
break
;
}
}
string
=
s
+
1
;
if
(
*
string
==
'#'
)
{
/* hexstring */
string
++
;
for
(
s
=
string
;
hexdigitp
(
s
);
s
++
)
s
++
;
n
=
s
-
string
;
if
(
!
n
||
(
n
&
1
))
return
NULL
;
/* Empty or odd number of digits. */
n
/=
2
;
array
->
value
=
p
=
xtrymalloc
(
n
+
1
);
if
(
!
p
)
return
NULL
;
for
(
s1
=
string
;
n
;
s1
+=
2
,
n
--
,
p
++
)
{
*
p
=
xtoi_2
(
s1
);
if
(
!*
p
)
*
p
=
0x01
;
/* Better print a wrong value than truncating
the string. */
}
*
p
=
0
;
}
else
{
/* regular v3 quoted string */
for
(
n
=
0
,
s
=
string
;
*
s
;
s
++
)
{
if
(
*
s
==
'\\'
)
{
/* pair */
s
++
;
if
(
*
s
==
','
||
*
s
==
'='
||
*
s
==
'+'
||
*
s
==
'<'
||
*
s
==
'>'
||
*
s
==
'#'
||
*
s
==
';'
||
*
s
==
'\\'
||
*
s
==
'\"'
||
*
s
==
' '
)
n
++
;
else
if
(
hexdigitp
(
s
)
&&
hexdigitp
(
s
+
1
))
{
s
++
;
n
++
;
}
else
return
NULL
;
/* invalid escape sequence */
}
else
if
(
*
s
==
'\"'
)
return
NULL
;
/* invalid encoding */
else
if
(
*
s
==
','
||
*
s
==
'='
||
*
s
==
'+'
||
*
s
==
'<'
||
*
s
==
'>'
||
*
s
==
'#'
||
*
s
==
';'
)
break
;
else
n
++
;
}
array
->
value
=
p
=
xtrymalloc
(
n
+
1
);
if
(
!
p
)
return
NULL
;
for
(
s
=
string
;
n
;
s
++
,
n
--
)
{
if
(
*
s
==
'\\'
)
{
s
++
;
if
(
hexdigitp
(
s
))
{
*
p
++
=
xtoi_2
(
s
);
s
++
;
}
else
*
p
++
=
*
s
;
}
else
*
p
++
=
*
s
;
}
*
p
=
0
;
}
return
s
;
}
/* Parse a DN and return an array-ized one. This is not a validating
parser and it does not support any old-stylish syntax; KSBA is
expected to return only rfc2253 compatible strings. */
static
struct
dn_array_s
*
parse_dn
(
const
unsigned
char
*
string
)
{
struct
dn_array_s
*
array
;
size_t
arrayidx
,
arraysize
;
int
i
;
arraysize
=
7
;
/* C,ST,L,O,OU,CN,email */
arrayidx
=
0
;
array
=
xtrymalloc
((
arraysize
+
1
)
*
sizeof
*
array
);
if
(
!
array
)
return
NULL
;
while
(
*
string
)
{
while
(
*
string
==
' '
)
string
++
;
if
(
!*
string
)
break
;
/* ready */
if
(
arrayidx
>=
arraysize
)
{
struct
dn_array_s
*
a2
;
arraysize
+=
5
;
a2
=
xtryrealloc
(
array
,
(
arraysize
+
1
)
*
sizeof
*
array
);
if
(
!
a2
)
goto
failure
;
array
=
a2
;
}
array
[
arrayidx
].
key
=
NULL
;
array
[
arrayidx
].
value
=
NULL
;
string
=
parse_dn_part
(
array
+
arrayidx
,
string
);
if
(
!
string
)
goto
failure
;
while
(
*
string
==
' '
)
string
++
;
array
[
arrayidx
].
multivalued
=
(
*
string
==
'+'
);
array
[
arrayidx
].
done
=
0
;
arrayidx
++
;
if
(
*
string
&&
*
string
!=
','
&&
*
string
!=
';'
&&
*
string
!=
'+'
)
goto
failure
;
/* invalid delimiter */
if
(
*
string
)
string
++
;
}
array
[
arrayidx
].
key
=
NULL
;
array
[
arrayidx
].
value
=
NULL
;
return
array
;
failure
:
for
(
i
=
0
;
i
<
arrayidx
;
i
++
)
{
xfree
(
array
[
i
].
key
);
xfree
(
array
[
i
].
value
);
}
xfree
(
array
);
return
NULL
;
}
static
void
print_dn_part
(
FILE
*
fp
,
struct
dn_array_s
*
dn
,
const
char
*
key
)
{
struct
dn_array_s
*
first_dn
=
dn
;
for
(;
dn
->
key
;
dn
++
)
{
if
(
!
dn
->
done
&&
!
strcmp
(
dn
->
key
,
key
))
{
/* Forward to the last multi-valued RDN, so that we can
print them all in reverse in the correct order. Note
that this overrides the the standard sequence but that
seems to a reasonable thing to do with multi-valued
RDNs. */
while
(
dn
->
multivalued
&&
dn
[
1
].
key
)
dn
++
;
next
:
if
(
!
dn
->
done
&&
dn
->
value
&&
*
dn
->
value
)
{
fprintf
(
fp
,
"/%s="
,
dn
->
key
);
print_sanitized_utf8_string
(
fp
,
dn
->
value
,
'/'
);
}
dn
->
done
=
1
;
if
(
dn
>
first_dn
&&
dn
[
-1
].
multivalued
)
{
dn
--
;
goto
next
;
}
}
}
}
/* Print all parts of a DN in a "standard" sequence. We first print
all the known parts, followed by the uncommon ones */
static
void
print_dn_parts
(
FILE
*
fp
,
struct
dn_array_s
*
dn
)
{
const
char
*
stdpart
[]
=
{
"CN"
,
"OU"
,
"O"
,
"STREET"
,
"L"
,
"ST"
,
"C"
,
"EMail"
,
NULL
};
int
i
;
for
(
i
=
0
;
stdpart
[
i
];
i
++
)
print_dn_part
(
fp
,
dn
,
stdpart
[
i
]);
/* Now print the rest without any specific ordering */
for
(;
dn
->
key
;
dn
++
)
print_dn_part
(
fp
,
dn
,
dn
->
key
);
}
void
gpgsm_print_name
(
FILE
*
fp
,
const
char
*
name
)
{
const
unsigned
char
*
s
;
int
i
;
s
=
name
;
if
(
!
s
)
{
fputs
(
_
(
"[Error - No name]"
),
fp
);
}
else
if
(
*
s
==
'<'
)
{
const
unsigned
char
*
s2
=
strchr
(
s
+
1
,
'>'
);
if
(
s2
)
print_sanitized_utf8_buffer
(
fp
,
s
+
1
,
s2
-
s
-
1
,
0
);
}
else
if
(
*
s
==
'('
)
fputs
(
_
(
"[Error - unknown encoding]"
),
fp
);
else
if
(
!
((
*
s
>=
'0'
&&
*
s
<
'9'
)
||
(
*
s
>=
'A'
&&
*
s
<=
'Z'
)
||
(
*
s
>=
'a'
&&
*
s
<=
'z'
)))
fputs
(
_
(
"[Error - invalid encoding]"
),
fp
);
else
{
struct
dn_array_s
*
dn
=
parse_dn
(
s
);
if
(
!
dn
)
fputs
(
_
(
"[Error - invalid DN]"
),
fp
);
else
{
print_dn_parts
(
fp
,
dn
);
for
(
i
=
0
;
dn
[
i
].
key
;
i
++
)
{
xfree
(
dn
[
i
].
key
);
xfree
(
dn
[
i
].
value
);
}
xfree
(
dn
);
}
}
}
/* A cookie structure used for the memory stream. */
struct
format_name_cookie
{
char
*
buffer
;
/* Malloced buffer with the data to deliver. */
size_t
size
;
/* Allocated size of this buffer. */
size_t
len
;
/* strlen (buffer). */
int
error
;
/* system error code if any. */
};
/* The writer function for the memory stream. */
static
int
format_name_writer
(
void
*
cookie
,
const
char
*
buffer
,
size_t
size
)
{
struct
format_name_cookie
*
c
=
cookie
;
char
*
p
;
if
(
c
->
buffer
)
p
=
xtryrealloc
(
c
->
buffer
,
c
->
size
+
size
+
1
);
else
p
=
xtrymalloc
(
size
+
1
);
if
(
!
p
)
{
c
->
error
=
errno
;
xfree
(
c
->
buffer
);
errno
=
c
->
error
;
return
-1
;
}
c
->
buffer
=
p
;
memcpy
(
p
+
c
->
len
,
buffer
,
size
);
c
->
len
+=
size
;
p
[
c
->
len
]
=
0
;
/* Terminate string. */
return
size
;
}
/* Format NAME which is expected to be in rfc2253 format into a better
human readable format. Caller must free the returned string. NULL
is returned in case of an error. */
char
*
gpgsm_format_name
(
const
char
*
name
)
{
#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
FILE
*
fp
;
struct
format_name_cookie
cookie
;
memset
(
&
cookie
,
0
,
sizeof
cookie
);
#ifdef HAVE_FOPENCOOKIE
{
cookie_io_functions_t
io
=
{
NULL
};
io
.
write
=
format_name_writer
;
fp
=
fopencookie
(
&
cookie
,
"w"
,
io
);
}
#else
/*!HAVE_FOPENCOOKIE*/
{
fp
=
funopen
(
&
cookie
,
NULL
,
format_name_writer
,
NULL
,
NULL
);
}
#endif
/*!HAVE_FOPENCOOKIE*/
if
(
!
fp
)
{
int
save_errno
=
errno
;
log_error
(
"error creating memory stream: %s
\n
"
,
strerror
(
errno
));
errno
=
save_errno
;
return
NULL
;
}
gpgsm_print_name
(
fp
,
name
);
fclose
(
fp
);
if
(
cookie
.
error
||
!
cookie
.
buffer
)
{
xfree
(
cookie
.
buffer
);
errno
=
cookie
.
error
;
return
NULL
;
}
return
cookie
.
buffer
;
#else
/* No fun - use the name verbatim. */
return
xtrystrdup
(
name
);
#endif
/* No fun. */
}
/* Create a key description for the CERT, this may be passed to the
pinentry. The caller must free the returned string. NULL may be
returned on error. */
char
*
gpgsm_format_keydesc
(
ksba_cert_t
cert
)
{
int
rc
;
char
*
name
,
*
subject
,
*
buffer
,
*
p
;
const
char
*
s
;
ksba_isotime_t
t
;
char
created
[
20
];
char
*
sn
;
ksba_sexp_t
sexp
;
char
*
orig_codeset
=
NULL
;
name
=
ksba_cert_get_subject
(
cert
,
0
);
subject
=
name
?
gpgsm_format_name
(
name
)
:
NULL
;
ksba_free
(
name
);
name
=
NULL
;
sexp
=
ksba_cert_get_serial
(
cert
);
sn
=
sexp
?
gpgsm_format_serial
(
sexp
)
:
NULL
;
ksba_free
(
sexp
);
ksba_cert_get_validity
(
cert
,
0
,
t
);
if
(
t
&&
*
t
)
sprintf
(
created
,
"%.4s-%.2s-%.2s"
,
t
,
t
+
4
,
t
+
6
);
else
*
created
=
0
;
#ifdef ENABLE_NLS
/* The Assuan agent protol requires us to transmit utf-8 strings */
orig_codeset
=
bind_textdomain_codeset
(
PACKAGE_GT
,
NULL
);
#ifdef HAVE_LANGINFO_CODESET
if
(
!
orig_codeset
)
orig_codeset
=
nl_langinfo
(
CODESET
);
#endif
if
(
orig_codeset
)
{
/* We only switch when we are able to restore the codeset later. */
orig_codeset
=
xstrdup
(
orig_codeset
);
if
(
!
bind_textdomain_codeset
(
PACKAGE_GT
,
"utf-8"
))
orig_codeset
=
NULL
;
}
#endif
rc
=
asprintf
(
&
name
,
_
(
"Please enter the passphrase to unlock the"
" secret key for:
\n
"
"
\"
%s
\"\n
"
"S/N %s, ID %08lX, created %s"
),
subject
?
subject
:
"?"
,
sn
?
sn
:
"?"
,
gpgsm_get_short_fingerprint
(
cert
),
created
);
#ifdef ENABLE_NLS
if
(
orig_codeset
)
bind_textdomain_codeset
(
PACKAGE_GT
,
orig_codeset
);
#endif
xfree
(
orig_codeset
);
if
(
rc
<
0
)
{
int
save_errno
=
errno
;
xfree
(
subject
);
xfree
(
sn
);
errno
=
save_errno
;
return
NULL
;
}
xfree
(
subject
);
xfree
(
sn
);
buffer
=
p
=
xtrymalloc
(
strlen
(
name
)
*
3
+
1
);
for
(
s
=
name
;
*
s
;
s
++
)
{
if
(
*
s
<
' '
||
*
s
==
'+'
)
{
sprintf
(
p
,
"%%%02X"
,
*
(
unsigned
char
*
)
s
);
p
+=
3
;
}
else
if
(
*
s
==
' '
)
*
p
++
=
'+'
;
else
*
p
++
=
*
s
;
}
*
p
=
0
;
free
(
name
);
return
buffer
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Feb 15, 3:45 PM (14 h, 16 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b9/6e/81ad0cd0b56219d20873b9d0f0ae
Attached To
rG GnuPG
Event Timeline
Log In to Comment