Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
aports
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Monitor
Service Desk
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
alpine
aports
Commits
691cd0fb
Commit
691cd0fb
authored
8 years ago
by
Timo Teräs
Browse files
Options
Downloads
Patches
Plain Diff
main/ca-certificates: add really the c_rehash sources
parent
11bef327
Loading
Loading
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
main/ca-certificates/c_rehash.c
+375
-0
375 additions, 0 deletions
main/ca-certificates/c_rehash.c
with
375 additions
and
0 deletions
main/ca-certificates/c_rehash.c
0 → 100644
+
375
−
0
View file @
691cd0fb
/* c_rehash.c - Create hash symlinks for certificates
* C implementation based on the original Perl and shell versions
*
* Copyright (c) 2013-2014 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This software is licensed under the MIT License.
* Full license available at: http://opensource.org/licenses/MIT
*/
#include
<stdio.h>
#include
<limits.h>
#include
<string.h>
#include
<unistd.h>
#include
<dirent.h>
#include
<sys/stat.h>
#include
<openssl/evp.h>
#include
<openssl/pem.h>
#include
<openssl/x509.h>
#define MAX_COLLISIONS 256
#define countof(x) (sizeof(x) / sizeof(x[0]))
#if 0
#define DEBUG(args...) fprintf(stderr, args)
#else
#define DEBUG(args...)
#endif
struct
entry_info
{
struct
entry_info
*
next
;
char
*
filename
;
unsigned
short
old_id
;
unsigned
char
need_symlink
;
unsigned
char
digest
[
EVP_MAX_MD_SIZE
];
};
struct
bucket_info
{
struct
bucket_info
*
next
;
struct
entry_info
*
first_entry
,
*
last_entry
;
unsigned
int
hash
;
unsigned
short
type
;
unsigned
short
num_needed
;
};
enum
Type
{
TYPE_CERT
=
0
,
TYPE_CRL
};
static
const
char
*
symlink_extensions
[]
=
{
""
,
"r"
};
static
const
char
*
file_extensions
[]
=
{
"pem"
,
"crt"
,
"cer"
,
"crl"
};
static
int
evpmdsize
;
static
const
EVP_MD
*
evpmd
;
static
int
do_hash_new
=
1
;
static
int
do_hash_old
=
0
;
static
int
do_remove_links
=
1
;
static
int
do_verbose
=
0
;
static
struct
bucket_info
*
hash_table
[
257
];
static
void
bit_set
(
unsigned
char
*
set
,
unsigned
bit
)
{
set
[
bit
/
8
]
|=
1
<<
(
bit
%
8
);
}
static
int
bit_isset
(
unsigned
char
*
set
,
unsigned
bit
)
{
return
set
[
bit
/
8
]
&
(
1
<<
(
bit
%
8
));
}
static
void
add_entry
(
int
type
,
unsigned
int
hash
,
const
char
*
filename
,
const
unsigned
char
*
digest
,
int
need_symlink
,
unsigned
short
old_id
)
{
struct
bucket_info
*
bi
;
struct
entry_info
*
ei
,
*
found
=
NULL
;
unsigned
int
ndx
=
(
type
+
hash
)
%
countof
(
hash_table
);
for
(
bi
=
hash_table
[
ndx
];
bi
;
bi
=
bi
->
next
)
if
(
bi
->
type
==
type
&&
bi
->
hash
==
hash
)
break
;
if
(
!
bi
)
{
bi
=
calloc
(
1
,
sizeof
(
*
bi
));
if
(
!
bi
)
return
;
bi
->
next
=
hash_table
[
ndx
];
bi
->
type
=
type
;
bi
->
hash
=
hash
;
hash_table
[
ndx
]
=
bi
;
}
for
(
ei
=
bi
->
first_entry
;
ei
;
ei
=
ei
->
next
)
{
if
(
digest
&&
memcmp
(
digest
,
ei
->
digest
,
evpmdsize
)
==
0
)
{
fprintf
(
stderr
,
"WARNING: Skipping duplicate certificate in file %s
\n
"
,
filename
);
return
;
}
if
(
!
strcmp
(
filename
,
ei
->
filename
))
{
found
=
ei
;
if
(
!
digest
)
break
;
}
}
ei
=
found
;
if
(
!
ei
)
{
if
(
bi
->
num_needed
>=
MAX_COLLISIONS
)
return
;
ei
=
calloc
(
1
,
sizeof
(
*
ei
));
if
(
!
ei
)
return
;
ei
->
old_id
=
~
0
;
ei
->
filename
=
strdup
(
filename
);
if
(
bi
->
last_entry
)
bi
->
last_entry
->
next
=
ei
;
if
(
!
bi
->
first_entry
)
bi
->
first_entry
=
ei
;
bi
->
last_entry
=
ei
;
}
if
(
old_id
<
ei
->
old_id
)
ei
->
old_id
=
old_id
;
if
(
need_symlink
&&
!
ei
->
need_symlink
)
{
ei
->
need_symlink
=
1
;
bi
->
num_needed
++
;
memcpy
(
ei
->
digest
,
digest
,
evpmdsize
);
}
}
static
int
handle_symlink
(
const
char
*
filename
,
const
char
*
fullpath
)
{
static
char
xdigit
[]
=
{
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
10
,
11
,
12
,
13
,
14
,
15
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
10
,
11
,
12
,
13
,
14
,
15
};
char
linktarget
[
NAME_MAX
],
*
endptr
;
unsigned
int
hash
=
0
;
unsigned
char
ch
;
int
i
,
type
,
id
;
ssize_t
n
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
ch
=
filename
[
i
]
-
'0'
;
if
(
ch
>=
countof
(
xdigit
)
||
xdigit
[
ch
]
<
0
)
return
-
1
;
hash
<<=
4
;
hash
+=
xdigit
[
ch
];
}
if
(
filename
[
i
++
]
!=
'.'
)
return
-
1
;
for
(
type
=
countof
(
symlink_extensions
)
-
1
;
type
>
0
;
type
--
)
if
(
strcasecmp
(
symlink_extensions
[
type
],
&
filename
[
i
])
==
0
)
break
;
i
+=
strlen
(
symlink_extensions
[
type
]);
id
=
strtoul
(
&
filename
[
i
],
&
endptr
,
10
);
if
(
*
endptr
!=
0
)
return
-
1
;
n
=
readlink
(
fullpath
,
linktarget
,
sizeof
(
linktarget
));
if
(
n
>=
sizeof
(
linktarget
)
||
n
<
0
)
return
-
1
;
linktarget
[
n
]
=
0
;
DEBUG
(
"Found existing symlink %s for %08x (%d), certname %s
\n
"
,
filename
,
hash
,
type
,
linktarget
);
add_entry
(
type
,
hash
,
linktarget
,
NULL
,
0
,
id
);
return
0
;
}
static
int
handle_certificate
(
const
char
*
filename
,
const
char
*
fullpath
)
{
STACK_OF
(
X509_INFO
)
*
inf
;
X509_INFO
*
x
;
BIO
*
b
;
const
char
*
ext
;
unsigned
char
digest
[
EVP_MAX_MD_SIZE
];
X509_NAME
*
name
=
NULL
;
int
i
,
type
,
ret
=
-
1
;
ext
=
strrchr
(
filename
,
'.'
);
if
(
ext
==
NULL
)
return
0
;
for
(
i
=
0
;
i
<
countof
(
file_extensions
);
i
++
)
{
if
(
strcasecmp
(
file_extensions
[
i
],
ext
+
1
)
==
0
)
break
;
}
if
(
i
>=
countof
(
file_extensions
))
return
-
1
;
b
=
BIO_new_file
(
fullpath
,
"r"
);
if
(
!
b
)
return
-
1
;
inf
=
PEM_X509_INFO_read_bio
(
b
,
NULL
,
NULL
,
NULL
);
BIO_free
(
b
);
if
(
!
inf
)
return
-
1
;
if
(
sk_X509_INFO_num
(
inf
)
==
1
)
{
x
=
sk_X509_INFO_value
(
inf
,
0
);
if
(
x
->
x509
)
{
type
=
TYPE_CERT
;
name
=
X509_get_subject_name
(
x
->
x509
);
X509_digest
(
x
->
x509
,
evpmd
,
digest
,
NULL
);
}
else
if
(
x
->
crl
)
{
type
=
TYPE_CRL
;
name
=
X509_CRL_get_issuer
(
x
->
crl
);
X509_CRL_digest
(
x
->
crl
,
evpmd
,
digest
,
NULL
);
}
if
(
name
&&
do_hash_new
)
add_entry
(
type
,
X509_NAME_hash
(
name
),
filename
,
digest
,
1
,
~
0
);
if
(
name
&&
do_hash_old
)
add_entry
(
type
,
X509_NAME_hash_old
(
name
),
filename
,
digest
,
1
,
~
0
);
}
else
{
fprintf
(
stderr
,
"WARNING: %s does not contain exactly one certificate or CRL: skipping
\n
"
,
filename
);
}
sk_X509_INFO_pop_free
(
inf
,
X509_INFO_free
);
return
ret
;
}
static
int
hash_dir
(
const
char
*
dirname
)
{
struct
bucket_info
*
bi
,
*
nextbi
;
struct
entry_info
*
ei
,
*
nextei
;
struct
dirent
*
de
;
struct
stat
st
;
unsigned
char
idmask
[
MAX_COLLISIONS
/
8
];
int
i
,
n
,
nextid
,
buflen
,
ret
=
-
1
;
const
char
*
pathsep
;
char
*
buf
;
DIR
*
d
;
if
(
access
(
dirname
,
R_OK
|
W_OK
|
X_OK
)
!=
0
)
{
fprintf
(
stderr
,
"ERROR: Access denied '%s'
\n
"
,
dirname
);
return
-
1
;
}
buflen
=
strlen
(
dirname
);
pathsep
=
(
buflen
&&
dirname
[
buflen
-
1
]
==
'/'
)
?
""
:
"/"
;
buflen
+=
NAME_MAX
+
2
;
buf
=
malloc
(
buflen
);
if
(
buf
==
NULL
)
goto
err
;
if
(
do_verbose
)
printf
(
"Doing %s
\n
"
,
dirname
);
d
=
opendir
(
dirname
);
if
(
!
d
)
goto
err
;
while
((
de
=
readdir
(
d
))
!=
NULL
)
{
if
(
snprintf
(
buf
,
buflen
,
"%s%s%s"
,
dirname
,
pathsep
,
de
->
d_name
)
>=
buflen
)
continue
;
if
(
lstat
(
buf
,
&
st
)
<
0
)
continue
;
if
(
S_ISLNK
(
st
.
st_mode
)
&&
handle_symlink
(
de
->
d_name
,
buf
)
==
0
)
continue
;
handle_certificate
(
de
->
d_name
,
buf
);
}
closedir
(
d
);
for
(
i
=
0
;
i
<
countof
(
hash_table
);
i
++
)
{
for
(
bi
=
hash_table
[
i
];
bi
;
bi
=
nextbi
)
{
nextbi
=
bi
->
next
;
DEBUG
(
"Type %d, hash %08x, num entries %d:
\n
"
,
bi
->
type
,
bi
->
hash
,
bi
->
num_needed
);
nextid
=
0
;
memset
(
idmask
,
0
,
(
bi
->
num_needed
+
7
)
/
8
);
for
(
ei
=
bi
->
first_entry
;
ei
;
ei
=
ei
->
next
)
if
(
ei
->
old_id
<
bi
->
num_needed
)
bit_set
(
idmask
,
ei
->
old_id
);
for
(
ei
=
bi
->
first_entry
;
ei
;
ei
=
nextei
)
{
nextei
=
ei
->
next
;
DEBUG
(
"
\t
(old_id %d, need_symlink %d) Cert %s
\n
"
,
ei
->
old_id
,
ei
->
need_symlink
,
ei
->
filename
);
if
(
ei
->
old_id
<
bi
->
num_needed
)
{
/* Link exists, and is used as-is */
snprintf
(
buf
,
buflen
,
"%08x.%s%d"
,
bi
->
hash
,
symlink_extensions
[
bi
->
type
],
ei
->
old_id
);
if
(
do_verbose
)
printf
(
"link %s -> %s
\n
"
,
ei
->
filename
,
buf
);
}
else
if
(
ei
->
need_symlink
)
{
/* New link needed (it may replace something) */
while
(
bit_isset
(
idmask
,
nextid
))
nextid
++
;
snprintf
(
buf
,
buflen
,
"%s%s%n%08x.%s%d"
,
dirname
,
pathsep
,
&
n
,
bi
->
hash
,
symlink_extensions
[
bi
->
type
],
nextid
);
if
(
do_verbose
)
printf
(
"link %s -> %s
\n
"
,
ei
->
filename
,
&
buf
[
n
]);
unlink
(
buf
);
symlink
(
ei
->
filename
,
buf
);
}
else
if
(
do_remove_links
)
{
/* Link to be deleted */
snprintf
(
buf
,
buflen
,
"%s%s%n%08x.%s%d"
,
dirname
,
pathsep
,
&
n
,
bi
->
hash
,
symlink_extensions
[
bi
->
type
],
ei
->
old_id
);
if
(
do_verbose
)
printf
(
"unlink %s
\n
"
,
&
buf
[
n
]);
unlink
(
buf
);
}
free
(
ei
->
filename
);
free
(
ei
);
}
free
(
bi
);
}
hash_table
[
i
]
=
NULL
;
}
ret
=
0
;
err:
free
(
buf
);
return
ret
;
}
static
void
c_rehash_usage
(
void
)
{
printf
(
"\
usage: c_rehash <args> <dirs>
\n
\
\n
\
-compat - create new- and old-style hashed links
\n
\
-old - use old-style hashing for generating links
\n
\
-h - display this help
\n
\
-n - do not remove existing links
\n
\
-v - be more verbose
\n
\
\n
"
);
}
int
main
(
int
argc
,
char
**
argv
)
{
const
char
*
env
,
*
opt
;
int
i
,
numargs
,
r
=
0
;
evpmd
=
EVP_sha1
();
evpmdsize
=
EVP_MD_size
(
evpmd
);
numargs
=
argc
;
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
if
(
argv
[
i
][
0
]
!=
'-'
)
continue
;
if
(
strcmp
(
argv
[
i
],
"--"
)
==
0
)
{
argv
[
i
]
=
0
;
numargs
--
;
break
;
}
opt
=
&
argv
[
i
][
1
];
if
(
strcmp
(
opt
,
"compat"
)
==
0
)
{
do_hash_new
=
do_hash_old
=
1
;
}
else
if
(
strcmp
(
opt
,
"old"
)
==
0
)
{
do_hash_new
=
0
;
do_hash_old
=
1
;
}
else
if
(
strcmp
(
opt
,
"n"
)
==
0
)
{
do_remove_links
=
0
;
}
else
if
(
strcmp
(
opt
,
"v"
)
==
0
)
{
do_verbose
++
;
}
else
{
if
(
strcmp
(
opt
,
"h"
)
!=
0
)
fprintf
(
stderr
,
"unknown option %s
\n
"
,
argv
[
i
]);
c_rehash_usage
();
return
1
;
}
argv
[
i
]
=
0
;
numargs
--
;
}
if
(
numargs
>
1
)
{
for
(
i
=
1
;
i
<
argc
;
i
++
)
if
(
argv
[
i
])
r
|=
hash_dir
(
argv
[
i
]);
}
else
if
((
env
=
getenv
(
"SSL_CERT_DIR"
))
!=
NULL
)
{
char
*
e
,
*
m
;
m
=
strdup
(
env
);
for
(
e
=
strtok
(
m
,
":"
);
e
!=
NULL
;
e
=
strtok
(
NULL
,
":"
))
r
|=
hash_dir
(
e
);
free
(
m
);
}
else
{
r
|=
hash_dir
(
"/etc/ssl/certs"
);
}
return
r
?
2
:
0
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment