Initial commit

This commit is contained in:
Reyk Floeter 2017-06-29 11:40:48 +02:00
commit 1c7148f25b
48 changed files with 19200 additions and 0 deletions

14
Makefile Normal file
View file

@ -0,0 +1,14 @@
#
# The Azure agents needs CMS to obtain the SSH public keys.
# LibreSSL has removed CMS, so either use OpenSSL to decrypt CMS
# messages or compile the old CMS code for LibreSSL.
#
.ifdef USE_OPENSSL
MAKE_FLAGS+= USE_OPENSSL=1
.else
SUBDIR= cms
.endif
SUBDIR+= agent
.include <bsd.subdir.mk>

4
README.md Normal file
View file

@ -0,0 +1,4 @@
NOTHING TO SEE HERE
===================
*...yet*

20
agent/Makefile Normal file
View file

@ -0,0 +1,20 @@
PROG= cloud-agent
SRCS= main.c xml.c azure.c cloudinit.c http.c log.c
BINDIR= /usr/local/libexec
.ifdef USE_OPENSSL
CFLAGS+= -DUSE_OPENSSL=1
.endif
CFLAGS+= -Wall
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith
CFLAGS+= -Wsign-compare -Wcast-qual
LDADD+= -lexpat -ltls -lssl -lcrypto
DPADD+= ${LIBEXPAT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
NOMAN= yes
.include <bsd.prog.mk>

791
agent/azure.c Normal file
View file

@ -0,0 +1,791 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/queue.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include "main.h"
#include "http.h"
#include "xml.h"
static struct azure_config {
const char *az_apiversion;
unsigned int az_incarnation;
const char *az_privkey;
const char *az_pubkey;
const char *az_certs;
char *az_pubkeyval;
char *az_container;
} az_config = {
.az_apiversion = "2015-04-05",
.az_incarnation = 1,
.az_privkey = "/var/db/azure-transport.key",
.az_pubkey = "/var/db/azure-transport.pub",
.az_certs = "/var/db/azure-certificates.pem"
};
static struct httpget
*azure_request(struct system_config *, struct xml *,
const char *, const void *, size_t, struct httphead **);
static int azure_keys(struct system_config *);
static int azure_getpubkeys(struct system_config *);
static int azure_getendpoint(struct system_config *);
static int azure_getovfenv(struct system_config *);
static int azure_versions(struct system_config *);
static int azure_goalstate(struct system_config *);
static int azure_certificates(struct system_config *);
static int azure_reporthealth(struct system_config *, const char *);
int
azure(struct system_config *sc)
{
int ret = -1;
/* Apply defaults */
if ((sc->sc_username = strdup("azure-user")) == NULL) {
log_warnx("failed to set default user");
goto done;
}
sc->sc_cdrom = "/dev/cd0c";
sc->sc_ovfenv = "/var/db/azure-ovf-env.xml";
sc->sc_priv = &az_config;
if (azure_getendpoint(sc) != 0) {
log_warnx("failed to get endpoint");
goto done;
}
if (azure_getovfenv(sc) != 0) {
log_warnx("failed to get ovf-env.xml");
goto done;
}
if (azure_versions(sc) != 0) {
log_warnx("failed to get endpoint versions");
goto done;
}
if (azure_goalstate(sc) != 0) {
log_warnx("failed to get goalstate");
goto done;
}
if (azure_keys(sc) != 0) {
log_warnx("failed to get transport keys");
goto done;
}
if (azure_certificates(sc) != 0) {
log_warnx("failed to get certificates");
goto done;
}
if (azure_reporthealth(sc, "Ready") != 0) {
log_warnx("failed to report health");
goto done;
}
ret = 0;
done:
free(az_config.az_container);
free(az_config.az_pubkeyval);
return (ret);
}
int
azure_keys(struct system_config *sc)
{
struct azure_config *az = sc->sc_priv;
int fd, i;
const char *k[4];
FILE *fp = NULL, *keyfp = NULL;
char buf[BUFSIZ];
char *keybuf = NULL;
size_t keybufsz;
k[0] = az->az_privkey;
k[1] = az->az_pubkey;
k[2] = az->az_certs;
k[3] = NULL;
if (access(az->az_privkey, R_OK) != 0 ||
access(az->az_pubkey, R_OK) != 0) {
/* Ugh, we must generate the files before writing the keys */
for (i = 0; k[i] != NULL; i++) {
if ((fd = open(k[i],
O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1)
return (-1);
close(fd);
}
fd = disable_output(sc, STDERR_FILENO);
/* Now generate the actual transport keys */
if (shell("openssl", "req",
"-x509", "-nodes", "-subj", "/CN=LinuxTransport",
"-days", "32768", "-newkey", "rsa:2048",
"-keyout", az->az_privkey,
"-out", az->az_pubkey,
NULL) != 0) {
log_debug("%s: failed to generate keys", __func__);
return (-1);
}
enable_output(sc, STDERR_FILENO, fd);
}
if ((fp = fopen(az->az_pubkey, "r")) == NULL) {
log_debug("%s: failed to read public key", __func__);
goto done;
}
if ((keyfp = open_memstream(&keybuf, &keybufsz)) == NULL) {
log_debug("%s: failed to open public key stream", __func__);
goto done;
}
/* We have to read the public key into a single base64 line */
while (fgets(buf, sizeof(buf), fp) != NULL) {
buf[strcspn(buf, "\r\n")] = '\0';
if (strcmp("-----BEGIN CERTIFICATE-----", buf) == 0 ||
strcmp("-----END CERTIFICATE-----", buf) == 0 ||
strlen(buf) < 1)
continue;
if (fputs(buf, keyfp) < 0) {
log_debug("%s: failed to write public key",
__func__);
goto done;
}
}
fclose(keyfp);
keyfp = NULL;
az->az_pubkeyval = keybuf;
done:
if (fp != NULL)
fclose(fp);
if (keyfp != NULL) {
fclose(keyfp);
free(keybuf);
}
return (0);
}
struct httpget *
azure_request(struct system_config *sc, struct xml *xml, const char *path,
const void *post, size_t postsz, struct httphead **head)
{
struct azure_config *az = sc->sc_priv;
struct httpget *g = NULL;
struct httphead **reqhead = NULL;
int i;
if (xml != NULL && xml_init(xml) != 0)
return (NULL);
for (i = 0; head != NULL && head[i] != NULL; i++)
;
if ((reqhead = calloc(i + 3, sizeof(struct httphead *))) == NULL) {
log_debug("%s: head", __func__);
goto fail;
}
for (i = 0; head != NULL && head[i] != NULL; i++)
reqhead[i] = head[i];
reqhead[i++] = &(struct httphead){ "x-ms-agent-name", "cloud-agent" };
reqhead[i++] = &(struct httphead){ "x-ms-version", az->az_apiversion };
reqhead[i++] = NULL;
g = http_get(&sc->sc_addr, 1,
sc->sc_endpoint, 80, path, post, postsz, reqhead);
if (g == NULL || g->code != 200) {
log_debug("%s: invalid response", __func__);
goto fail;
}
free(reqhead);
if (xml == NULL) {
if (log_getverbose() > 2)
fwrite(g->bodypart, g->bodypartsz, 1, stderr);
return (g);
}
if (g->bodypartsz < 1 ||
xml_parse_buffer(xml, g->bodypart, g->bodypartsz) != 0) {
log_debug("%s: xml", __func__);
goto fail;
}
if (log_getverbose() > 2)
xml_print(xml, TAILQ_FIRST(&xml->ox_root), 0, stderr);
return (g);
fail:
xml_free(xml);
if (reqhead != NULL)
free(reqhead);
if (g != NULL)
http_get_free(g);
return (NULL);
}
static int
azure_versions(struct system_config *sc)
{
struct azure_config *az = sc->sc_priv;
struct httpget *g;
struct xmlelem *xe, *xv;
int ret = -1;
struct xml xml;
if ((g = azure_request(sc, &xml, "/?comp=versions",
NULL, 0, NULL)) == NULL)
goto done;
if ((xe = xml_findl(&xml.ox_root,
"Versions", "Supported", NULL)) == NULL) {
log_debug("%s: unexpected xml document", __func__);
goto done;
}
TAILQ_FOREACH(xv, &xe->xe_head, xe_entry) {
if (strcmp("Version", xv->xe_tag) == 0 &&
strcmp(xv->xe_data, az->az_apiversion) == 0) {
/* success! */
log_debug("%s: API version %s", __func__, xv->xe_data);
ret = 0;
break;
}
}
done:
xml_free(&xml);
http_get_free(g);
return (ret);
}
static int
azure_goalstate(struct system_config *sc)
{
struct azure_config *az = sc->sc_priv;
struct httpget *g;
struct xmlelem *xe;
int ret = -1;
struct xml xml;
const char *errstr = NULL;
if ((g = azure_request(sc, &xml, "/machine/?comp=goalstate",
NULL, 0, NULL)) == NULL)
goto done;
if ((xe = xml_findl(&xml.ox_root,
"GoalState", "Version", NULL)) == NULL ||
strcmp(xe->xe_data, az->az_apiversion) != 0) {
log_debug("%s: unexpected API version", __func__);
goto done;
}
if ((xe = xml_findl(&xml.ox_root,
"GoalState", "Incarnation", NULL)) == NULL) {
log_debug("%s: unexpected incarnation", __func__);
goto done;
}
az->az_incarnation = strtonum(xe->xe_data, 1, INT_MAX, &errstr);
if (errstr != NULL) {
log_debug("%s: unexpected incarnation: %s", __func__, errstr);
goto done;
}
if ((xe = xml_findl(&xml.ox_root,
"GoalState", "Container", "ContainerId", NULL)) == NULL ||
(az->az_container = strdup(xe->xe_data)) == NULL) {
log_debug("%s: unexpected container id", __func__);
goto done;
}
if ((xe = xml_findl(&xml.ox_root,
"GoalState", "Container", "RoleInstanceList",
"RoleInstance", "InstanceId", NULL)) == NULL ||
(sc->sc_instance = strdup(xe->xe_data)) == NULL) {
log_debug("%s: unexpected instance id", __func__);
goto done;
}
log_debug("%s: container %s instance %s incarnation %d", __func__,
az->az_container, sc->sc_instance, az->az_incarnation);
ret = 0;
done:
xml_free(&xml);
http_get_free(g);
return (ret);
}
static int
azure_certificates(struct system_config *sc)
{
struct azure_config *az = sc->sc_priv;
struct httpget *g;
struct httphead *reqhead[3];
int ret = -1;
char *req = NULL;
char tmp1[32], tmp2[32];
struct xml xml;
struct xmlelem *xe, *data;
int fd;
memset(tmp1, 0, sizeof(tmp1));
memset(tmp2, 0, sizeof(tmp2));
reqhead[0] = &(struct httphead){ "x-ms-cipher-name", "DES_EDE3_CBC" };
reqhead[1] = &(struct httphead){
"x-ms-guest-agent-public-x509-cert", az->az_pubkeyval
};
reqhead[2] = NULL;
if (asprintf(&req, "/machine/%s/%s?comp=certificates&incarnation=%d",
az->az_container, sc->sc_instance, az->az_incarnation) == -1)
return (-1);
g = azure_request(sc, &xml, req, NULL, 0, reqhead);
http_get_free(g);
free(req);
req = NULL;
/* certificates are optional and only needed w/o password auth */
if (g == NULL)
return (0);
if ((xe = xml_findl(&xml.ox_root,
"CertificateFile", "Version", NULL)) == NULL ||
strcmp(xe->xe_data, az->az_apiversion) != 0) {
log_debug("%s: unexpected API version", __func__);
goto done;
}
if ((xe = xml_findl(&xml.ox_root,
"CertificateFile", "Format", NULL)) == NULL ||
strcmp(xe->xe_data, "Pkcs7BlobWithPfxContents") != 0) {
log_debug("%s: unexpected format", __func__);
goto done;
}
if ((data = xml_findl(&xml.ox_root,
"CertificateFile", "Data", NULL)) == NULL) {
log_debug("%s: no data", __func__);
goto done;
}
/* Write CMS blob to temporary file */
strlcpy(tmp1, "/tmp/azure-cms.XXXXXXXX", sizeof(tmp1));
if ((fd = mkstemp(tmp1)) == -1) {
log_debug("%s: failed to write data", __func__);
goto done;
}
dprintf(fd, "MIME-Version: 1.0\n"
"Content-Disposition: attachment; filename=\"smime.p7m\"\n"
"Content-Type: application/pkcs7-mime;"
" smime-type=enveloped-data; name=\"smime.p7m\"\n"
"Content-Transfer-Encoding: base64\n"
"\n%s",
data->xe_data);
close(fd);
strlcpy(tmp2, "/tmp/azure-pkcs12.XXXXXXXX", sizeof(tmp2));
if ((fd = mkstemp(tmp2)) == -1) {
log_debug("%s: failed to write data", __func__);
goto done;
}
close(fd);
fd = disable_output(sc, STDERR_FILENO);
#ifdef USE_OPENSSL
/*
* XXX Now comes the part that needs CMS which is only
* XXX present in OpenSSL but got removed from LibreSSL.
*/
log_debug("%s: running openssl cms", __func__);
if (shell("/usr/local/bin/eopenssl", "cms", /* )) */
#else
if (shell("/usr/local/bin/cms",
#endif
"-decrypt", "-inkey", az->az_privkey, "-des3",
"-in", tmp1, "-out", tmp2, NULL) != 0) {
enable_output(sc, STDERR_FILENO, fd);
log_debug("%s: failed to decrypt CMS blob", __func__);
goto done;
}
unlink(tmp1);
/* Decrypt PKCS12 blob (now with LibreSSL) */
if (shell("openssl", "pkcs12",
"-nodes", "-password", "pass:",
"-in", tmp2, "-out", az->az_certs, NULL) != 0) {
enable_output(sc, STDERR_FILENO, fd);
log_debug("%s: failed to decrypt PKCS12 blob", __func__);
goto done;
}
unlink(tmp2);
enable_output(sc, STDERR_FILENO, fd);
/*
* XXX the following could be done using libcrypto directly
*/
ret = azure_getpubkeys(sc);
done:
unlink(tmp1);
unlink(tmp2);
xml_free(&xml);
return (ret);
}
int
azure_getpubkeys(struct system_config *sc)
{
struct azure_config *az = sc->sc_priv;
char buf[BUFSIZ];
char *in = NULL, *out = NULL, *p, *v;
FILE *fp;
int ret = -1;
FILE *infp = NULL;
char *inbuf;
size_t inbufsz;
if ((fp = fopen(az->az_certs, "r")) == NULL) {
log_debug("%s: failed to read certificates", __func__);
goto done;
}
/* Read all certificates */
while (fgets(buf, sizeof(buf), fp) != NULL) {
buf[strcspn(buf, "\r\n")] = '\0';
if (strcmp("-----BEGIN CERTIFICATE-----", buf) == 0) {
if ((infp = open_memstream(&inbuf, &inbufsz)) == NULL) {
log_debug("%s: failed to write cert", __func__);
goto done;
}
} else if (infp == NULL)
continue;
fprintf(infp, "%s\n", buf);
if (strcmp("-----END CERTIFICATE-----", buf) == 0) {
fclose(infp);
infp = NULL;
/* Convert certificate into public key */
if (shellout(inbuf, &in,
"openssl", "x509", "-fingerprint", "-pubkey",
"-noout", NULL) != 0) {
log_debug("%s: could not get public key",
__func__);
goto done;
}
free(inbuf);
inbuf = NULL;
/* Convert public key into SSH key */
if (shellout(in, &out,
"ssh-keygen", "-i", "-m", "PKCS8",
"-f", "/dev/stdin", NULL) == -1) {
log_debug("%s: could not get ssh key",
__func__);
goto done;
}
/* Get public key fingerprint */
if ((p = strstr(in, "Fingerprint=")) == NULL) {
log_debug("%s: could not get fingerprint",
__func__);
goto done;
}
p[strcspn(p, "\r\n")] = '\0';
p += strlen("Fingerprint=");
/* Strip colons */
for (v = p + strlen(p); v != p; v--)
if (*v == ':')
memmove(v, v + 1, strlen(v));
if (agent_setpubkey(sc, out, p) > 0)
log_debug("%s: public key %s", __func__, p);
free(in);
in = NULL;
free(out);
out = NULL;
}
}
ret = 0;
done:
free(inbuf);
free(in);
free(out);
return (ret);
}
static int
azure_reporthealth(struct system_config *sc, const char *message)
{
struct azure_config *az = sc->sc_priv;
struct httpget *g = NULL;
struct httphead *httph, *reqhead[2];
const char *errstr = NULL;
size_t httphsz, i;
int ret = -1;
char *req;
int reqsz;
const char *state;
reqhead[0] = &(struct httphead){
"Content-Type", "text/xml; charset=utf-8"
};
reqhead[1] = NULL;
if (strcmp("Ready", message) == 0) {
state = "<State>Ready</State>";
} else {
state =
"<State>NotReady</State>\n"
"<Details>\n"
"<SubStatus>Provisioning</SubStatus>\n"
"<Description>Starting</Description>\n"
"</Details>";
}
reqsz = asprintf(&req,
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<Health xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n"
"<GoalStateIncarnation>%u</GoalStateIncarnation>\n"
"<Container>\n"
"<ContainerId>%s</ContainerId>\n"
"<RoleInstanceList>\n"
"<Role>\n"
"<InstanceId>%s</InstanceId>\n"
"<Health>%s</Health>\n"
"</Role>\n"
"</RoleInstanceList>\n"
"</Container>\n"
"</Health>\n",
az->az_incarnation,
az->az_container,
sc->sc_instance,
state);
if (reqsz == -1)
goto done;
if ((g = azure_request(sc, NULL, "/machine/?comp=health",
req, reqsz, reqhead)) == NULL)
goto done;
httph = http_head_parse(g->http, g->xfer, &httphsz);
for (i = 0; i < httphsz; i++) {
if (strcmp(httph[i].key,
"x-ms-latest-goal-state-incarnation-number") == 0) {
az->az_incarnation =
strtonum(httph[i].val, 1, INT_MAX, &errstr);
if (errstr != NULL) {
log_debug("%s: unexpected incarnation: %s",
__func__, errstr);
goto done;
}
ret = 0;
break;
}
}
if (ret != 0)
goto done;
log_debug("%s: %s, incarnation %u", __func__,
message, az->az_incarnation);
done:
http_get_free(g);
return (ret);
}
static int
azure_getovfenv(struct system_config *sc)
{
struct xml xml;
struct xmlelem *xp, *xe, *xk, *xv;
const char *sshfp, *sshval;
int mount = 0, ret = -1, fd = -1;
FILE *fp;
/* try to mount the cdrom */
if (shell("mount", "-r", sc->sc_cdrom, "/mnt", NULL) == 0) {
log_debug("%s: mounted %s", __func__, sc->sc_cdrom);
mount = 1;
}
if (xml_init(&xml) != 0) {
log_debug("%s: xml", __func__);
goto done;
}
xml_parse(&xml, "/mnt/ovf-env.xml");
/* unmount if we mounted the cdrom before */
if (mount && shell("umount", "/mnt", NULL) == 0) {
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
}
if ((xp = xml_findl(&xml.ox_root,
"Environment", "wa:ProvisioningSection",
"LinuxProvisioningConfigurationSet", NULL)) == NULL) {
log_debug("%s: could not find OVF structure", __func__);
goto done;
}
if ((xe = xml_findl(&xp->xe_head,
"SSH", "PublicKeys", NULL)) != NULL) {
/* Find all (optional) SSH keys */
TAILQ_FOREACH(xk, &xe->xe_head, xe_entry) {
if (strcasecmp(xk->xe_tag, "PublicKey") != 0)
continue;
sshfp = sshval = NULL;
if ((xv = xml_findl(&xk->xe_head,
"Fingerprint", NULL)) != NULL)
sshfp = xv->xe_data;
if ((xv = xml_findl(&xk->xe_head,
"Value", NULL)) != NULL)
sshval = xv->xe_data;
if (agent_addpubkey(sc, sshval, sshfp) != 0)
log_warnx("failed to add ssh pubkey");
}
}
if ((xe = xml_findl(&xp->xe_head, "HostName", NULL)) != NULL) {
if ((sc->sc_hostname = strdup(xe->xe_data)) == NULL) {
log_debug("%s: hostname failed", __func__);
goto done;
}
}
if ((xe = xml_findl(&xp->xe_head, "UserName", NULL)) != NULL) {
free(sc->sc_username);
if ((sc->sc_username = strdup(xe->xe_data)) == NULL) {
log_debug("%s: username failed", __func__);
goto done;
}
}
if ((xe = xml_findl(&xp->xe_head, "UserPassword", NULL)) != NULL) {
if ((sc->sc_password = calloc(1, 128)) == NULL ||
crypt_newhash(xe->xe_data, "bcrypt,a",
sc->sc_password, 128) != 0) {
log_debug("%s: password failed", __func__);
goto done;
}
}
if ((fd = open(sc->sc_ovfenv, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1 ||
(fp = fdopen(fd, "w")) == NULL) {
log_debug("%s: failed to open %s", __func__, sc->sc_ovfenv);
goto done;
}
xml_print(&xml, TAILQ_FIRST(&xml.ox_root), 0, fp);
fclose(fp);
log_debug("%s: wrote %s", __func__, sc->sc_ovfenv);
ret = 0;
done:
if (fd != -1)
close(fd);
xml_free(&xml);
return (ret);
}
static int
azure_getendpoint(struct system_config *sc)
{
char path[PATH_MAX], buf[BUFSIZ], *ep = NULL;
int a[4];
FILE *fp;
if ((size_t)snprintf(path, sizeof(path), "/var/db/dhclient.leases.%s",
sc->sc_interface) >= sizeof(path)) {
log_debug("%s: invalid path", __func__);
return (-1);
}
if ((fp = fopen(path, "r")) == NULL) {
log_debug("%s: failed to open %s", __func__, path);
return (-1);
}
while (fgets(buf, sizeof(buf), fp) != NULL) {
buf[strcspn(buf, ";\n")] = '\0';
/* Find last occurence of option-245 */
if (sscanf(buf, " option option-245 %x:%x:%x:%x",
&a[0], &a[1], &a[2], &a[3]) == 4) {
free(ep);
if (asprintf(&ep, "%d.%d.%d.%d",
a[0], a[1], a[2], a[3]) == -1) {
log_debug("%s: asprintf", __func__);
return (-1);
}
}
}
fclose(fp);
if (ep == NULL) {
log_debug("%s: endpoint not found", __func__);
return (-1);
}
sc->sc_endpoint = ep;
sc->sc_addr.ip = sc->sc_endpoint;
sc->sc_addr.family = 4;
log_debug("%s: %s", __func__, ep);
return (0);
}

117
agent/cloudinit.c Normal file
View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/queue.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include "main.h"
#include "http.h"
#include "xml.h"
static int cloudinit_fetch(struct system_config *);
static char *cloudinit_get(struct system_config *, const char *, size_t *);
int
ec2(struct system_config *sc)
{
if ((sc->sc_username = strdup("ec2-user")) == NULL ||
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
log_warnx("failed to set defaults");
return (-1);
}
return (cloudinit_fetch(sc));
}
int
cloudinit(struct system_config *sc)
{
/* XXX get endpoint from DHCP lease file */
if ((sc->sc_username = strdup("puffy")) == NULL ||
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
log_warnx("failed to set defaults");
return (-1);
}
return (cloudinit_fetch(sc));
}
static char *
cloudinit_get(struct system_config *sc, const char *path, size_t *strsz)
{
struct httpget *g = NULL;
char *str = NULL;
log_debug("%s: %s", __func__, path);
g = http_get(&sc->sc_addr, 1,
sc->sc_endpoint, 80, path, NULL, 0, NULL);
if (g != NULL && g->code == 200 && g->bodypartsz > 0) {
if ((str = calloc(1, g->bodypartsz + 1)) != NULL) {
memcpy(str, g->bodypart, g->bodypartsz);
if (strsz != NULL)
*strsz = g->bodypartsz;
}
}
http_get_free(g);
return (str);
}
static int
cloudinit_fetch(struct system_config *sc)
{
int ret = 0;
char *str = NULL;
sc->sc_addr.ip = sc->sc_endpoint;
sc->sc_addr.family = 4;
/* hostname */
if ((sc->sc_instance = cloudinit_get(sc,
"/latest/meta-data/instance-id", NULL)) == NULL)
goto fail;
/* hostname */
if ((sc->sc_hostname = cloudinit_get(sc,
"/latest/meta-data/local-hostname", NULL)) == NULL)
goto fail;
/* pubkey */
if ((str = cloudinit_get(sc,
"/latest/meta-data/public-keys/0/openssh-key", NULL)) == NULL)
goto fail;
if (agent_addpubkey(sc, str, NULL) != 0)
goto fail;
/* userdata */
if ((sc->sc_userdata = cloudinit_get(sc,
"/latest/user-data", &sc->sc_userdatalen)) == NULL)
goto fail;
ret = 0;
fail:
free(str);
return (ret);
}

818
agent/http.c Normal file
View file

@ -0,0 +1,818 @@
/* $Id: http.c,v 1.20 2017/03/26 18:41:02 deraadt Exp $ */
/*
* Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
#include <err.h>
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <tls.h>
#include <unistd.h>
#include "http.h"
#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
/*
* A buffer for transferring HTTP/S data.
*/
struct httpxfer {
char *hbuf; /* header transfer buffer */
size_t hbufsz; /* header buffer size */
int headok; /* header has been parsed */
char *bbuf; /* body transfer buffer */
size_t bbufsz; /* body buffer size */
int bodyok; /* body has been parsed */
char *headbuf; /* lookaside buffer for headers */
struct httphead *head; /* parsed headers */
size_t headsz; /* number of headers */
};
/*
* An HTTP/S connection object.
*/
struct http {
int fd; /* connected socket */
short port; /* port number */
struct source src; /* endpoint (raw) host */
char *path; /* path to request */
char *host; /* name of endpoint host */
struct tls *ctx; /* if TLS */
writefp writer; /* write function */
readfp reader; /* read function */
};
struct tls_config *tlscfg;
static ssize_t
dosysread(char *buf, size_t sz, const struct http *http)
{
ssize_t rc;
rc = read(http->fd, buf, sz);
if (rc < 0)
warn("%s: read", http->src.ip);
return rc;
}
static ssize_t
dosyswrite(const void *buf, size_t sz, const struct http *http)
{
ssize_t rc;
rc = write(http->fd, buf, sz);
if (rc < 0)
warn("%s: write", http->src.ip);
return rc;
}
static ssize_t
dotlsread(char *buf, size_t sz, const struct http *http)
{
ssize_t rc;
do {
rc = tls_read(http->ctx, buf, sz);
} while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
if (rc < 0)
warnx("%s: tls_read: %s", http->src.ip,
tls_error(http->ctx));
return rc;
}
static ssize_t
dotlswrite(const void *buf, size_t sz, const struct http *http)
{
ssize_t rc;
do {
rc = tls_write(http->ctx, buf, sz);
} while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
if (rc < 0)
warnx("%s: tls_write: %s", http->src.ip,
tls_error(http->ctx));
return rc;
}
int
http_init()
{
if (tlscfg != NULL)
return 0;
if (tls_init() == -1) {
warn("tls_init");
goto err;
}
tlscfg = tls_config_new();
if (tlscfg == NULL) {
warn("tls_config_new");
goto err;
}
if (tls_config_set_ca_file(tlscfg, DEFAULT_CA_FILE) == -1) {
warn("tls_config_set_ca_file: %s", tls_config_error(tlscfg));
goto err;
}
return 0;
err:
tls_config_free(tlscfg);
tlscfg = NULL;
return -1;
}
static ssize_t
http_read(char *buf, size_t sz, const struct http *http)
{
ssize_t ssz, xfer;
xfer = 0;
do {
if ((ssz = http->reader(buf, sz, http)) < 0)
return -1;
if (ssz == 0)
break;
xfer += ssz;
sz -= ssz;
buf += ssz;
} while (ssz > 0 && sz > 0);
return xfer;
}
static int
http_write(const char *buf, size_t sz, const struct http *http)
{
ssize_t ssz, xfer;
xfer = sz;
while (sz > 0) {
if ((ssz = http->writer(buf, sz, http)) < 0)
return -1;
sz -= ssz;
buf += (size_t)ssz;
}
return xfer;
}
void
http_disconnect(struct http *http)
{
int rc;
if (http->ctx != NULL) {
/* TLS connection. */
do {
rc = tls_close(http->ctx);
} while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
if (rc < 0)
warnx("%s: tls_close: %s", http->src.ip,
tls_error(http->ctx));
tls_free(http->ctx);
}
if (http->fd != -1) {
if (close(http->fd) == -1)
warn("%s: close", http->src.ip);
}
http->fd = -1;
http->ctx = NULL;
}
void
http_free(struct http *http)
{
if (http == NULL)
return;
http_disconnect(http);
free(http->host);
free(http->path);
free(http->src.ip);
free(http);
}
struct http *
http_alloc(const struct source *addrs, size_t addrsz,
const char *host, short port, const char *path)
{
struct sockaddr_storage ss;
int family, fd, c;
socklen_t len;
size_t cur, i = 0;
struct http *http;
/* Do this while we still have addresses to connect. */
again:
if (i == addrsz)
return NULL;
cur = i++;
/* Convert to PF_INET or PF_INET6 address from string. */
memset(&ss, 0, sizeof(struct sockaddr_storage));
if (addrs[cur].family == 4) {
family = PF_INET;
((struct sockaddr_in *)&ss)->sin_family = AF_INET;
((struct sockaddr_in *)&ss)->sin_port = htons(port);
c = inet_pton(AF_INET, addrs[cur].ip,
&((struct sockaddr_in *)&ss)->sin_addr);
len = sizeof(struct sockaddr_in);
} else if (addrs[cur].family == 6) {
family = PF_INET6;
((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6;
((struct sockaddr_in6 *)&ss)->sin6_port = htons(port);
c = inet_pton(AF_INET6, addrs[cur].ip,
&((struct sockaddr_in6 *)&ss)->sin6_addr);
len = sizeof(struct sockaddr_in6);
} else {
warnx("%s: unknown family", addrs[cur].ip);
goto again;
}
if (c < 0) {
warn("%s: inet_ntop", addrs[cur].ip);
goto again;
} else if (c == 0) {
warnx("%s: inet_ntop", addrs[cur].ip);
goto again;
}
/* Create socket and connect. */
fd = socket(family, SOCK_STREAM, 0);
if (fd == -1) {
warn("%s: socket", addrs[cur].ip);
goto again;
} else if (connect(fd, (struct sockaddr *)&ss, len) == -1) {
warn("%s: connect", addrs[cur].ip);
close(fd);
goto again;
}
/* Allocate the communicator. */
http = calloc(1, sizeof(struct http));
if (http == NULL) {
warn("calloc");
close(fd);
return NULL;
}
http->fd = fd;
http->port = port;
http->src.family = addrs[cur].family;
http->src.ip = strdup(addrs[cur].ip);
http->host = strdup(host);
http->path = strdup(path);
if (http->src.ip == NULL || http->host == NULL || http->path == NULL) {
warn("strdup");
goto err;
}
/* If necessary, do our TLS setup. */
if (port != 443) {
http->writer = dosyswrite;
http->reader = dosysread;
return http;
}
http->writer = dotlswrite;
http->reader = dotlsread;
if ((http->ctx = tls_client()) == NULL) {
warn("tls_client");
goto err;
} else if (tls_configure(http->ctx, tlscfg) == -1) {
warnx("%s: tls_configure: %s",
http->src.ip, tls_error(http->ctx));
goto err;
}
if (tls_connect_socket(http->ctx, http->fd, http->host) != 0) {
warnx("%s: tls_connect_socket: %s, %s", http->src.ip,
http->host, tls_error(http->ctx));
goto err;
}
return http;
err:
http_free(http);
return NULL;
}
static int
http_head_write(struct httphead **head, const struct http *http)
{
char *req = NULL;
int i, c;
if (head == NULL)
return (0);
for (i = 0; head[i] != NULL && head[i]->key != NULL; i++) {
/* Append terminating \r\n after last header line */
c = asprintf(&req, "%s: %s\r\n%s", head[i]->key, head[i]->val,
head[i + 1] == NULL ? "\r\n" : "");
if (!http_write(req, c, http)) {
free(req);
return (-1);
}
free(req);
}
return (0);
}
struct httpxfer *
http_open(const struct http *http, const void *p, size_t psz,
struct httphead **reqhead)
{
char *req;
int c;
struct httpxfer *trans;
if (p == NULL) {
c = asprintf(&req,
"GET %s HTTP/1.0\r\n"
"Host: %s\r\n%s",
http->path, http->host,
reqhead != NULL ? "" : "\r\n");
} else {
c = asprintf(&req,
"POST %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Content-Length: %zu\r\n%s",
http->path, http->host, psz,
reqhead != NULL ? "" : "\r\n");
}
if (c == -1) {
warn("asprintf");
return NULL;
} else if (!http_write(req, c, http)) {
free(req);
return NULL;
} else if (http_head_write(reqhead, http) != 0) {
free(req);
return NULL;
} else if (p != NULL && !http_write(p, psz, http)) {
free(req);
return NULL;
}
free(req);
trans = calloc(1, sizeof(struct httpxfer));
if (trans == NULL)
warn("calloc");
return trans;
}
void
http_close(struct httpxfer *x)
{
if (x == NULL)
return;
free(x->hbuf);
free(x->bbuf);
free(x->headbuf);
free(x->head);
free(x);
}
/*
* Read the HTTP body from the wire.
* If invoked multiple times, this will return the same pointer with the
* same data (or NULL, if the original invocation returned NULL).
* Returns NULL if read or allocation errors occur.
* You must not free the returned pointer.
*/
char *
http_body_read(const struct http *http, struct httpxfer *trans, size_t *sz)
{
char buf[BUFSIZ];
ssize_t ssz;
void *pp;
size_t szp;
if (sz == NULL)
sz = &szp;
/* Have we already parsed this? */
if (trans->bodyok > 0) {
*sz = trans->bbufsz;
return trans->bbuf;
} else if (trans->bodyok < 0)
return NULL;
*sz = 0;
trans->bodyok = -1;
do {
/* If less than sizeof(buf), at EOF. */
if ((ssz = http_read(buf, sizeof(buf), http)) < 0)
return NULL;
else if (ssz == 0)
break;
pp = recallocarray(trans->bbuf,
trans->bbufsz, trans->bbufsz + ssz, 1);
if (pp == NULL) {
warn("recallocarray");
return NULL;
}
trans->bbuf = pp;
memcpy(trans->bbuf + trans->bbufsz, buf, ssz);
trans->bbufsz += ssz;
} while (ssz == sizeof(buf));
trans->bodyok = 1;
*sz = trans->bbufsz;
return trans->bbuf;
}
struct httphead *
http_head_get(const char *v, struct httphead *h, size_t hsz)
{
size_t i;
for (i = 0; i < hsz; i++) {
if (strcmp(h[i].key, v))
continue;
return &h[i];
}
return NULL;
}
/*
* Look through the headers and determine our HTTP code.
* This will return -1 on failure, otherwise the code.
*/
int
http_head_status(const struct http *http, struct httphead *h, size_t sz)
{
int rc;
unsigned int code;
struct httphead *st;
if ((st = http_head_get("Status", h, sz)) == NULL) {
warnx("%s: no status header", http->src.ip);
return -1;
}
rc = sscanf(st->val, "%*s %u %*s", &code);
if (rc < 0) {
warn("sscanf");
return -1;
} else if (rc != 1) {
warnx("%s: cannot convert status header", http->src.ip);
return -1;
}
return code;
}
/*
* Parse headers from the transfer.
* Malformed headers are skipped.
* A special "Status" header is added for the HTTP status line.
* This can only happen once http_head_read has been called with
* success.
* This can be invoked multiple times: it will only parse the headers
* once and after that it will just return the cache.
* You must not free the returned pointer.
* If the original header parse failed, or if memory allocation fails
* internally, this returns NULL.
*/
struct httphead *
http_head_parse(const struct http *http, struct httpxfer *trans, size_t *sz)
{
size_t hsz, szp;
struct httphead *h;
char *cp, *ep, *ccp, *buf;
if (sz == NULL)
sz = &szp;
/*
* If we've already parsed the headers, return the
* previously-parsed buffer now.
* If we have errors on the stream, return NULL now.
*/
if (trans->head != NULL) {
*sz = trans->headsz;
return trans->head;
} else if (trans->headok <= 0)
return NULL;
if ((buf = strdup(trans->hbuf)) == NULL) {
warn("strdup");
return NULL;
}
hsz = 0;
cp = buf;
do {
if ((cp = strstr(cp, "\r\n")) != NULL)
cp += 2;
hsz++;
} while (cp != NULL);
/*
* Allocate headers, then step through the data buffer, parsing
* out headers as we have them.
* We know at this point that the buffer is NUL-terminated in
* the usual way.
*/
h = calloc(hsz, sizeof(struct httphead));
if (h == NULL) {
warn("calloc");
free(buf);
return NULL;
}
*sz = hsz;
hsz = 0;
cp = buf;
do {
if ((ep = strstr(cp, "\r\n")) != NULL) {
*ep = '\0';
ep += 2;
}
if (hsz == 0) {
h[hsz].key = "Status";
h[hsz++].val = cp;
continue;
}
/* Skip bad headers. */
if ((ccp = strchr(cp, ':')) == NULL) {
warnx("%s: header without separator", http->src.ip);
continue;
}
*ccp++ = '\0';
while (isspace((int)*ccp))
ccp++;
h[hsz].key = cp;
h[hsz++].val = ccp;
} while ((cp = ep) != NULL);
trans->headbuf = buf;
trans->head = h;
trans->headsz = hsz;
return h;
}
/*
* Read the HTTP headers from the wire.
* If invoked multiple times, this will return the same pointer with the
* same data (or NULL, if the original invocation returned NULL).
* Returns NULL if read or allocation errors occur.
* You must not free the returned pointer.
*/
char *
http_head_read(const struct http *http, struct httpxfer *trans, size_t *sz)
{
char buf[BUFSIZ];
ssize_t ssz;
char *ep;
void *pp;
size_t szp;
if (sz == NULL)
sz = &szp;
/* Have we already parsed this? */
if (trans->headok > 0) {
*sz = trans->hbufsz;
return trans->hbuf;
} else if (trans->headok < 0)
return NULL;
*sz = 0;
ep = NULL;
trans->headok = -1;
/*
* Begin by reading by BUFSIZ blocks until we reach the header
* termination marker (two CRLFs).
* We might read into our body, but that's ok: we'll copy out
* the body parts into our body buffer afterward.
*/
do {
/* If less than sizeof(buf), at EOF. */
if ((ssz = http_read(buf, sizeof(buf), http)) < 0)
return NULL;
else if (ssz == 0)
break;
pp = recallocarray(trans->hbuf,
trans->hbufsz, trans->hbufsz + ssz, 1);
if (pp == NULL) {
warn("recallocarray");
return NULL;
}
trans->hbuf = pp;
memcpy(trans->hbuf + trans->hbufsz, buf, ssz);
trans->hbufsz += ssz;
/* Search for end of headers marker. */
ep = memmem(trans->hbuf, trans->hbufsz, "\r\n\r\n", 4);
} while (ep == NULL && ssz == sizeof(buf));
if (ep == NULL) {
warnx("%s: partial transfer", http->src.ip);
return NULL;
}
*ep = '\0';
/*
* The header data is invalid if it has any binary characters in
* it: check that now.
* This is important because we want to guarantee that all
* header keys and pairs are properly NUL-terminated.
*/
if (strlen(trans->hbuf) != (uintptr_t)(ep - trans->hbuf)) {
warnx("%s: binary data in header", http->src.ip);
return NULL;
}
/*
* Copy remaining buffer into body buffer.
*/
ep += 4;
trans->bbufsz = (trans->hbuf + trans->hbufsz) - ep;
trans->bbuf = malloc(trans->bbufsz);
if (trans->bbuf == NULL) {
warn("malloc");
return NULL;
}
memcpy(trans->bbuf, ep, trans->bbufsz);
trans->headok = 1;
*sz = trans->hbufsz;
return trans->hbuf;
}
void
http_get_free(struct httpget *g)
{
if (g == NULL)
return;
http_close(g->xfer);
http_free(g->http);
free(g);
}
struct httpget *
http_get(const struct source *addrs, size_t addrsz, const char *domain,
short port, const char *path, const void *post, size_t postsz,
struct httphead **reqhead)
{
struct http *h;
struct httpxfer *x;
struct httpget *g;
struct httphead *head;
size_t headsz, bodsz, headrsz;
int code;
char *bod, *headr;
h = http_alloc(addrs, addrsz, domain, port, path);
if (h == NULL)
return NULL;
if ((x = http_open(h, post, postsz, reqhead)) == NULL) {
http_free(h);
return NULL;
} else if ((headr = http_head_read(h, x, &headrsz)) == NULL) {
http_close(x);
http_free(h);
return NULL;
} else if ((bod = http_body_read(h, x, &bodsz)) == NULL) {
http_close(x);
http_free(h);
return NULL;
}
http_disconnect(h);
if ((head = http_head_parse(h, x, &headsz)) == NULL) {
http_close(x);
http_free(h);
return NULL;
} else if ((code = http_head_status(h, head, headsz)) < 0) {
http_close(x);
http_free(h);
return NULL;
}
if ((g = calloc(1, sizeof(struct httpget))) == NULL) {
warn("calloc");
http_close(x);
http_free(h);
return NULL;
}
g->headpart = headr;
g->headpartsz = headrsz;
g->bodypart = bod;
g->bodypartsz = bodsz;
g->head = head;
g->headsz = headsz;
g->code = code;
g->xfer = x;
g->http = h;
return g;
}
#if 0
int
main(void)
{
struct httpget *g;
struct httphead *httph;
size_t i, httphsz;
struct source addrs[2];
size_t addrsz;
struct httphead *reqhead[3];
/* This could be allocated ;) */
reqhead[0] = &(struct httphead){ "X-Hello", "World" };
reqhead[1] = &(struct httphead){ "X-Test", "123" };
reqhead[2] = NULL;
#if 0
addrs[0].ip = "127.0.0.1";
addrs[0].family = 4;
addrsz = 1;
#else
addrs[0].ip = "2a00:1450:400a:806::2004";
addrs[0].family = 6;
addrs[1].ip = "193.135.3.123";
addrs[1].family = 4;
addrsz = 2;
#endif
if (http_init() == -1)
errx(EXIT_FAILURE, "http_init");
#if 0
g = http_get(addrs, addrsz, "localhost", 80, "/index.html",
NULL, 0, reqhead);
#else
g = http_get(addrs, addrsz, "www.google.ch", 80, "/index.html",
NULL, 0, reqhead);
#endif
if (g == NULL)
errx(EXIT_FAILURE, "http_get");
httph = http_head_parse(g->http, g->xfer, &httphsz);
warnx("code: %d", g->code);
for (i = 0; i < httphsz; i++)
warnx("head: [%s]=[%s]", httph[i].key, httph[i].val);
http_get_free(g);
return (EXIT_SUCCESS);
}
#endif

93
agent/http.h Normal file
View file

@ -0,0 +1,93 @@
/* $Id: http.h,v 1.5 2017/01/25 13:52:53 inoguchi Exp $ */
/*
* Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef HTTP_H
#define HTTP_H
struct source {
int family; /* 4 (PF_INET) or 6 (PF_INET6) */
char *ip; /* IPV4 or IPV6 address */
};
struct http;
/*
* Write and read callbacks to allow HTTP and HTTPS.
* Both of these return the number of bytes read (or written) or -1 on
* failure.
* 0 bytes read means that the connection has closed.
*/
typedef ssize_t (*writefp)(const void *, size_t, const struct http *);
typedef ssize_t (*readfp)(char *, size_t, const struct http *);
/*
* HTTP/S header pair.
* There's also a cooked-up pair, "Status", with the status code.
* Both strings are NUL-terminated.
*/
struct httphead {
const char *key;
const char *val;
};
/*
* Grab all information from a transfer.
* DO NOT free any parts of this, and editing the parts (e.g., changing
* the underlying strings) will persist; so in short, don't.
* All of these values will be set upon http_get() success.
*/
struct httpget {
struct httpxfer *xfer; /* underlying transfer */
struct http *http; /* underlying connection */
int code; /* return code */
struct httphead *head; /* headers */
size_t headsz; /* number of headers */
char *headpart; /* header buffer */
size_t headpartsz; /* size of headpart */
char *bodypart; /* body buffer */
size_t bodypartsz; /* size of bodypart */
};
int http_init(void);
/* Convenience functions. */
struct httpget *http_get(const struct source *, size_t,
const char *, short, const char *,
const void *, size_t, struct httphead **);
void http_get_free(struct httpget *);
/* Allocation and release. */
struct http *http_alloc(const struct source *, size_t,
const char *, short, const char *);
void http_free(struct http *);
struct httpxfer *http_open(const struct http *, const void *, size_t,
struct httphead **);
void http_close(struct httpxfer *);
void http_disconnect(struct http *);
/* Access. */
char *http_head_read(const struct http *,
struct httpxfer *, size_t *);
struct httphead *http_head_parse(const struct http *,
struct httpxfer *, size_t *);
char *http_body_read(const struct http *,
struct httpxfer *, size_t *);
int http_head_status(const struct http *,
struct httphead *, size_t);
struct httphead *http_head_get(const char *,
struct httphead *, size_t);
#endif /* HTTP_H */

218
agent/log.c Normal file
View file

@ -0,0 +1,218 @@
/* $OpenBSD: log.c,v 1.35 2017/03/21 12:06:56 bluhm Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <time.h>
static int debug;
static int verbose;
const char *log_procname;
void log_init(int, int);
void log_procinit(const char *);
void log_setverbose(int);
int log_getverbose(void);
void log_warn(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_warnx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_info(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_debug(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void logit(int, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
void vlog(int, const char *, va_list)
__attribute__((__format__ (printf, 2, 0)));
__dead void fatal(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
__dead void fatalx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void
log_init(int n_debug, int facility)
{
extern char *__progname;
debug = n_debug;
verbose = n_debug;
log_procinit(__progname);
if (!debug)
openlog(__progname, LOG_PID | LOG_NDELAY, facility);
tzset();
}
void
log_procinit(const char *procname)
{
if (procname != NULL)
log_procname = procname;
}
void
log_setverbose(int v)
{
verbose = v;
}
int
log_getverbose(void)
{
return (verbose);
}
void
logit(int pri, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vlog(pri, fmt, ap);
va_end(ap);
}
void
vlog(int pri, const char *fmt, va_list ap)
{
char *nfmt;
int saved_errno = errno;
if (debug) {
/* best effort in out of mem situations */
if (asprintf(&nfmt, "%s\n", fmt) == -1) {
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
} else {
vfprintf(stderr, nfmt, ap);
free(nfmt);
}
fflush(stderr);
} else
vsyslog(pri, fmt, ap);
errno = saved_errno;
}
void
log_warn(const char *emsg, ...)
{
char *nfmt;
va_list ap;
int saved_errno = errno;
/* best effort to even work in out of memory situations */
if (emsg == NULL)
logit(LOG_ERR, "%s", strerror(saved_errno));
else {
va_start(ap, emsg);
if (asprintf(&nfmt, "%s: %s", emsg,
strerror(saved_errno)) == -1) {
/* we tried it... */
vlog(LOG_ERR, emsg, ap);
logit(LOG_ERR, "%s", strerror(saved_errno));
} else {
vlog(LOG_ERR, nfmt, ap);
free(nfmt);
}
va_end(ap);
}
errno = saved_errno;
}
void
log_warnx(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vlog(LOG_ERR, emsg, ap);
va_end(ap);
}
void
log_info(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vlog(LOG_INFO, emsg, ap);
va_end(ap);
}
void
log_debug(const char *emsg, ...)
{
va_list ap;
if (verbose > 1) {
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
}
}
static void
vfatalc(int code, const char *emsg, va_list ap)
{
static char s[BUFSIZ];
const char *sep;
if (emsg != NULL) {
(void)vsnprintf(s, sizeof(s), emsg, ap);
sep = ": ";
} else {
s[0] = '\0';
sep = "";
}
if (code)
logit(LOG_CRIT, "%s: %s%s%s",
log_procname, s, sep, strerror(code));
else
logit(LOG_CRIT, "%s%s%s", log_procname, sep, s);
}
void
fatal(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vfatalc(errno, emsg, ap);
va_end(ap);
exit(1);
}
void
fatalx(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vfatalc(0, emsg, ap);
va_end(ap);
exit(1);
}

625
agent/main.c Normal file
View file

@ -0,0 +1,625 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/wait.h>
#include <sys/socket.h>
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "main.h"
#include "xml.h"
__dead void usage(void);
static struct system_config *agent_init(void);
static void agent_free(struct system_config *);
static int agent_pf(struct system_config *, int);
static void agent_unconfigure(void);
int
shell(const char *arg, ...)
{
const char **argv, *a;
int argc, i = 0, status;
va_list ap;
pid_t pid, child_pid;
struct sigaction sigint, sigquit;
sigset_t mask, omask;
/* create arguments */
va_start(ap, arg);
for (argc = 2; va_arg(ap, const char *) != NULL; argc++)
;
va_end(ap);
if ((argv = calloc(argc, sizeof(const char *))) == NULL)
fatal("%s: calloc", __func__);
argv[i++] = arg;
va_start(ap, arg);
while ((a = va_arg(ap, char *)) != NULL)
argv[i++] = a;
va_end(ap);
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &omask);
/* run command in forked process */
switch (child_pid = fork()) {
case -1:
sigprocmask(SIG_SETMASK, &omask, NULL);
free(argv);
return (-1);
case 0:
sigprocmask(SIG_SETMASK, &omask, NULL);
execvp(argv[0], (char *const *)(caddr_t)argv);
_exit(127);
}
free(argv);
sigaction(SIGINT, NULL, &sigint);
sigaction(SIGQUIT, NULL, &sigquit);
do {
pid = waitpid(child_pid, &status, 0);
} while (pid == -1 && errno == EINTR);
sigprocmask(SIG_SETMASK, &omask, NULL);
sigaction(SIGINT, &sigint, NULL);
sigaction(SIGQUIT, &sigquit, NULL);
/* Simplified return value: returns 0 on success and -1 on error */
if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
return (0);
return (-1);
}
int
shellout(const char *in, char **out, const char *arg, ...)
{
const char **argv = NULL, *a;
int argc, i = 0, status;
va_list ap;
pid_t pid, child_pid;
struct sigaction sigint, sigquit;
sigset_t mask, omask;
FILE *outfp = NULL, *fp = NULL;
char *outbuf;
size_t outbufsz;
char buf[BUFSIZ];
int fdi[2], fdo[2];
if (out)
*out = NULL;
/* create arguments */
va_start(ap, arg);
for (argc = 2; va_arg(ap, const char *) != NULL; argc++)
;
va_end(ap);
if ((argv = calloc(argc, sizeof(const char *))) == NULL)
fatal("%s: calloc", __func__);
argv[i++] = arg;
va_start(ap, arg);
while ((a = va_arg(ap, char *)) != NULL)
argv[i++] = a;
va_end(ap);
if (in && socketpair(AF_UNIX,
SOCK_STREAM|SOCK_CLOEXEC, AF_UNSPEC, fdi) == -1)
goto fail;
if (out && socketpair(AF_UNIX,
SOCK_STREAM|SOCK_CLOEXEC, AF_UNSPEC, fdo) == -1)
goto fail;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &omask);
/* run command in forked process */
switch (child_pid = fork()) {
case -1:
sigprocmask(SIG_SETMASK, &omask, NULL);
goto fail;
case 0:
if (in) {
close(fdi[1]);
if (dup2(fdi[0], STDIN_FILENO) == -1)
_exit(127);
}
if (out) {
close(fdo[1]);
if (dup2(fdo[0], STDOUT_FILENO) == -1)
_exit(127);
}
sigprocmask(SIG_SETMASK, &omask, NULL);
execvp(argv[0], (char *const *)(caddr_t)argv);
_exit(127);
}
free(argv);
sigaction(SIGINT, NULL, &sigint);
sigaction(SIGQUIT, NULL, &sigquit);
if (in) {
close(fdi[0]);
if ((fp = fdopen(fdi[1], "w")) != NULL) {
fputs(in, fp);
fflush(fp);
fclose(fp);
}
close(fdi[1]);
}
if (out) {
close(fdo[0]);
if ((fp = fdopen(fdo[1], "r")) != NULL &&
(outfp = open_memstream(&outbuf, &outbufsz)) != NULL) {
while (fgets(buf, sizeof(buf), fp) != NULL) {
fputs(buf, outfp);
}
fclose(outfp);
*out = outbuf;
}
fclose(fp);
close(fdo[1]);
}
do {
pid = waitpid(child_pid, &status, 0);
} while (pid == -1 && errno == EINTR);
sigprocmask(SIG_SETMASK, &omask, NULL);
sigaction(SIGINT, &sigint, NULL);
sigaction(SIGQUIT, &sigquit, NULL);
/* Simplified return value: returns 0 on success and -1 on error */
if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
return (0);
fail:
free(argv);
if (out) {
free(*out);
*out = NULL;
}
return (-1);
}
int
disable_output(struct system_config *sc, int fd)
{
int oldfd;
if (log_getverbose() > 2)
return (-1);
if ((oldfd = dup(fd)) == -1 ||
dup2(sc->sc_nullfd, fd) == -1)
return (-1);
return (oldfd);
}
int
enable_output(struct system_config *sc, int fd, int oldfd)
{
if (oldfd == -1)
return (0);
close(fd);
if (dup2(oldfd, fd) == -1)
return (-1);
return (0);
}
static struct system_config *
agent_init(void)
{
struct system_config *sc;
if ((sc = calloc(1, sizeof(*sc))) == NULL)
return (NULL);
TAILQ_INIT(&sc->sc_pubkeys);
if ((sc->sc_nullfd = open("/dev/null", O_RDWR)) == -1) {
free(sc);
return (NULL);
}
return (sc);
}
static void
agent_free(struct system_config *sc)
{
struct ssh_pubkey *ssh;
free(sc->sc_hostname);
free(sc->sc_username);
free(sc->sc_password);
free(sc->sc_userdata);
free(sc->sc_endpoint);
free(sc->sc_instance);
close(sc->sc_nullfd);
while ((ssh = TAILQ_FIRST(&sc->sc_pubkeys))) {
free(ssh->ssh_keyval);
free(ssh->ssh_keyfp);
TAILQ_REMOVE(&sc->sc_pubkeys, ssh, ssh_entry);
free(ssh);
}
}
int
agent_addpubkey(struct system_config *sc, const char *sshval, const char *sshfp)
{
struct ssh_pubkey *ssh;
/* Ignore if neither key nor fingerprint is available */
if (sshval == NULL && sshfp == NULL)
return (0);
if ((ssh = calloc(1, sizeof(*ssh))) == NULL)
return (-1);
if (sshfp != NULL && (ssh->ssh_keyfp = strdup(sshfp)) == NULL) {
free(ssh);
return (-1);
}
if (sshval != NULL && (ssh->ssh_keyval = strdup(sshval)) == NULL) {
free(ssh->ssh_keyfp);
free(ssh);
return (-1);
}
TAILQ_INSERT_TAIL(&sc->sc_pubkeys, ssh, ssh_entry);
return (0);
}
int
agent_setpubkey(struct system_config *sc, const char *sshval, const char *sshfp)
{
struct ssh_pubkey *ssh;
int ret = 0;
char *v = NULL;
TAILQ_FOREACH(ssh, &sc->sc_pubkeys, ssh_entry) {
if (sshfp && ssh->ssh_keyfp &&
strcasecmp(ssh->ssh_keyfp, sshfp) == 0) {
if ((sshval == NULL) ||
(sshval && (v = strdup(sshval)) == NULL))
break;
v[strcspn(v, "\r\n")] = '\0';
free(ssh->ssh_keyval);
ssh->ssh_keyval = v;
ret++;
}
}
return (ret);
}
static int
fileout(const char *str, const char *mode, const char *fmt, ...)
{
FILE *fp;
va_list ap;
char *path;
int ret;
va_start(ap, fmt);
ret = vasprintf(&path, fmt, ap);
va_end(ap);
if (ret == -1)
return (-1);
if ((fp = fopen(path, mode)) == NULL) {
free(path);
return (-1);
}
if (str != NULL) {
fputs(str, fp);
if (strpbrk(str, "\r\n") == NULL)
fputs("\n", fp);
}
fclose(fp);
free(path);
return (0);
}
static char *
filein(const char *mode, const char *fmt, ...)
{
FILE *fp;
va_list ap;
char *path;
int ret;
char buf[BUFSIZ];
FILE *infp;
char *inbuf;
size_t inbufsz;
va_start(ap, fmt);
ret = vasprintf(&path, fmt, ap);
va_end(ap);
if (ret == -1)
return (NULL);
if ((fp = fopen(path, mode)) == NULL) {
free(path);
return (NULL);
}
free(path);
if ((infp = open_memstream(&inbuf, &inbufsz)) == NULL)
fclose(fp);
while (fgets(buf, sizeof(buf), fp) != NULL) {
fputs(buf, infp);
}
fclose(fp);
fclose(infp);
return (inbuf);
}
static int
agent_pf(struct system_config *sc, int open)
{
int ret;
if (shell("rcctl", "get", "pf", "status", NULL) != 0)
return (0);
if (open)
ret = shellout("pass out proto tcp from egress to port www\n",
NULL, "pfctl", "-f", "-", NULL);
else
ret = shellout("\n", NULL, "pfctl", "-f", "-", NULL);
return (ret);
}
int
agent_configure(struct system_config *sc, int noaction)
{
struct ssh_pubkey *ssh;
char *str1, *str2;
/* Skip configuration on the same instance */
if ((str1 = filein("r", "/var/db/cloud-instance")) != NULL &&
strcmp(sc->sc_instance, str1) == 0) {
free(str1);
return (0);
}
free(str1);
if (!noaction &&
fileout(sc->sc_instance, "w", "/var/db/cloud-instance") != 0)
log_warnx("instance failed");
/* hostname */
log_debug("%s: hostname %s", __func__, sc->sc_hostname);
if (!noaction &&
fileout(sc->sc_hostname, "w", "/etc/myname") != 0)
log_warnx("hostname failed");
else
(void)shell("hostname", sc->sc_hostname, NULL);
/* username */
log_debug("%s: username %s", __func__, sc->sc_username);
if (!noaction &&
shell("useradd", "-L", "staff", "-G", "wheel",
"-m", sc->sc_username, NULL) != 0)
log_warnx("username failed");
/* password */
if (sc->sc_password == NULL) {
str1 = "/PasswordAuthentication/"
"s/.*/PasswordAuthentication no/";
str2 = "permit keepenv nopass :wheel as root\n"
"permit keepenv nopass root\n";
} else {
if (!noaction &&
shell("usermod", "-p", sc->sc_password,
sc->sc_username, NULL) != 0)
log_warnx("password failed");
str1 = "/PasswordAuthentication/"
"s/.*/PasswordAuthentication yes/";
str2 = "permit keepenv persist :wheel as root\n"
"permit keepenv nopass root\n";
}
/* doas */
if (fileout(str2, "w", "/etc/doas.conf") != 0)
log_warnx("doas failed");
/* ssh configuration */
if (sc->sc_password == NULL && !TAILQ_EMPTY(&sc->sc_pubkeys))
str1 = "/PasswordAuthentication/"
"s/.*/PasswordAuthentication no/";
else
str1 = "/PasswordAuthentication/"
"s/.*/PasswordAuthentication yes/";
shell("sed", "-i", "-e", str1,
"-e", "/ClientAliveInterval/s/.*/ClientAliveInterval 180/",
"/etc/ssh/sshd_config",
NULL);
/* ssh public keys */
TAILQ_FOREACH(ssh, &sc->sc_pubkeys, ssh_entry) {
if (ssh->ssh_keyval == NULL)
continue;
log_debug("%s: key %s", __func__, ssh->ssh_keyval);
if (!noaction &&
fileout(ssh->ssh_keyval, "a",
"/home/%s/.ssh/authorized_keys",
sc->sc_username) != 0)
log_warnx("public key failed");
}
if (sc->sc_userdata) {
/* XXX */
}
log_debug("%s: %s", __func__, "/etc/rc.firsttime");
if (!noaction && fileout("logger -s -t cloud-agent <<EOF\n"
"#############################################################\n"
"-----BEGIN SSH HOST KEY FINGERPRINTS-----\n"
"$(for _f in /etc/ssh/ssh_host_*_key.pub;"
" do ssh-keygen -lf ${_f}; done)\n"
"-----END SSH HOST KEY FINGERPRINTS-----\n"
"#############################################################\n"
"EOF\n",
"a", "/etc/rc.firsttime") != 0)
log_warnx("userdata failed");
return (0);
}
void
agent_unconfigure(void)
{
/* Disable root pasword */
(void)shell("chpass", "-a",
"root:*:0:0:daemon:0:0:Charlie &:/root:/bin/ksh", NULL);
/* Delete keys */
(void)shell("sh", "-c",
"rm -rf /etc/{iked,isakmpd}/{local.pub,private/local.key}"
" /etc/ssh/ssh_host_*"
" /etc/dhclient.conf /var/db/dhclient.leases.*"
" /tmp/{.[!.],}*", NULL);
/* Delete old seed files */
(void)fileout(NULL, "w", "/etc/random.seed");
(void)fileout(NULL, "w", "/var/db/host.random");
/* Clear logfiles */
(void)shell("sh", "-c",
"for _l in $(find /var/log -type f ! -name '*.gz' -size +0); do"
" >${_l}; "
"done", NULL);
(void)fileout("permit keepenv persist :wheel as root\n"
"permit keepenv nopass root\n", "w", "/etc/doas.conf");
}
__dead void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s [-nuv] interface\n",
__progname);
exit(1);
}
int
main(int argc, char *const *argv)
{
struct system_config *sc;
int verbose = 0, noaction = 0, unconfigure = 0;
int ch, ret;
while ((ch = getopt(argc, argv, "nvu")) != -1) {
switch (ch) {
case 'n':
noaction = 1;
break;
case 'v':
verbose += 2;
break;
case 'u':
unconfigure = 1;
break;
default:
usage();
}
}
argv += optind;
argc -= optind;
/* log to stderr */
log_init(1, LOG_DAEMON);
log_setverbose(verbose);
if (unconfigure) {
agent_unconfigure();
exit(0);
}
if (argc != 1)
usage();
if (pledge("stdio cpath rpath wpath exec proc dns inet", NULL) == -1)
fatal("pledge");
if ((sc = agent_init()) == NULL)
fatalx("agent");
sc->sc_interface = argv[0];
if (agent_pf(sc, 1) != 0)
fatalx("pf");
if (http_init() == -1)
fatalx("http_init");
/*
* XXX Detect cloud with help from hostctl and sysctl
* XXX in addition to the interface name.
*/
if (strcmp("hvn0", sc->sc_interface) == 0)
ret = azure(sc);
else if (strcmp("xnf0", sc->sc_interface) == 0)
ret = ec2(sc);
else if (strcmp("vio0", sc->sc_interface) == 0)
ret = cloudinit(sc);
else
fatal("unsupported cloud interface %s", sc->sc_interface);
if (agent_pf(sc, 0) != 0)
fatalx("pf");
if (pledge("stdio cpath rpath wpath exec proc", NULL) == -1)
fatal("pledge");
if (ret == 0 && agent_configure(sc, noaction) != 0)
fatal("provisioning failed");
agent_free(sc);
return (0);
}

94
agent/main.h Normal file
View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef MAIN_H
#define MAIN_H
#include <sys/queue.h>
#include <sys/cdefs.h>
#include <stdarg.h>
#include <stddef.h>
#include "http.h"
struct ssh_pubkey {
char *ssh_keyval;
char *ssh_keyfp;
TAILQ_ENTRY(ssh_pubkey) ssh_entry;
};
TAILQ_HEAD(ssh_pubkeys, ssh_pubkey);
struct system_config {
char *sc_hostname;
char *sc_username;
char *sc_password;
char *sc_pubkey;
unsigned char *sc_userdata;
size_t sc_userdatalen;
char *sc_endpoint;
char *sc_instance;
const char *sc_ovfenv;
const char *sc_interface;
const char *sc_cdrom;
struct source sc_addr;
struct ssh_pubkeys sc_pubkeys;
int sc_nullfd;
void *sc_priv;
};
/* azure.c */
int azure(struct system_config *);
/* cloudinit.c */
int ec2(struct system_config *);
int cloudinit(struct system_config *);
/* main.c */
int shell(const char *, ...);
int shellout(const char *, char **, const char *, ...);
int disable_output(struct system_config *, int);
int enable_output(struct system_config *, int, int);
int agent_addpubkey(struct system_config *, const char *, const char *);
int agent_setpubkey(struct system_config *, const char *, const char *);
int agent_configure(struct system_config *, int);
/* log.c */
void log_init(int, int);
void log_procinit(const char *);
void log_setverbose(int);
int log_getverbose(void);
void log_warn(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_warnx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_info(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_debug(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void logit(int, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
void vlog(int, const char *, va_list)
__attribute__((__format__ (printf, 2, 0)));
__dead void fatal(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
__dead void fatalx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
#endif /* MAIN_H */

363
agent/xml.c Normal file
View file

@ -0,0 +1,363 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <ctype.h>
#include <err.h>
#include <expat.h>
#include "main.h"
#include "xml.h"
static void xml_start_element(void *, const char *, const char **);
static void xml_end_element(void *, const char *);
static void xml_char_data(void *, const char *, int);
static void xml_inc(struct xmlelem *, int);
static void
xml_inc(struct xmlelem *b, int depth)
{
struct xmlelem *xe;
b->xe_depth += depth;
TAILQ_FOREACH(xe, &b->xe_head, xe_entry)
xml_inc(xe, depth);
}
void
xml_add(struct xmlelem *a, struct xmlelem *b)
{
xml_inc(b, a->xe_depth);
TAILQ_INSERT_TAIL(&a->xe_head, b, xe_entry);
}
void
xml_delete(struct xmlhead *xh)
{
struct xmlelem *xe, *tmp;
int i;
TAILQ_FOREACH_SAFE(xe, xh, xe_entry, tmp) {
xml_delete(&xe->xe_head);
TAILQ_REMOVE(xh, xe, xe_entry);
if (xe->xe_attr != NULL) {
for (i = 0; xe->xe_attr[i] != NULL; i++)
free(xe->xe_attr[i]);
free(xe->xe_attr);
}
free(xe->xe_data);
free(xe->xe_tag);
free(xe);
}
}
struct xmlelem *
xml_get(struct xmlhead *root, const char *arg)
{
struct xmlelem *xe;
TAILQ_FOREACH(xe, root, xe_entry) {
/* search case-insensitive */
if (strcasecmp(xe->xe_tag, arg) == 0)
return (xe);
}
return (NULL);
}
struct xmlelem *
xml_findv(struct xmlhead *root, const char **argv, int argc)
{
struct xmlelem *xe = NULL;
struct xmlhead *head = root;
int i;
for (i = 0; i < argc; i++) {
if ((xe = xml_get(head, argv[i])) == NULL)
break;
head = &xe->xe_head;
}
return (xe);
}
struct xmlelem *
xml_findl(struct xmlhead *root, const char *arg, ...)
{
struct xmlelem *xe = NULL;
const char **argv = NULL;
int argc, i;
const char *tag;
va_list ap;
va_start(ap, arg);
for (argc = 1; va_arg(ap, const char *) != NULL; argc++)
;
va_end(ap);
if ((argv = calloc(argc, sizeof(const char *))) == NULL)
fatal("calloc");
i = 0;
argv[i++] = arg;
va_start(ap, arg);
while ((tag = va_arg(ap, const char *)) != NULL)
argv[i++] = tag;
va_end(ap);
xe = xml_findv(root, argv, argc);
free(argv);
return (xe);
}
/*
* Print XML tree suitable for OVF
*
* This parser and printer does not support CDATA with embedded
* elements which is not required for OVF - it is more or less a simple
* key/value store without HTML-like markup.
*/
void
xml_print(struct xml *env, struct xmlelem *xe, int data_only, FILE *fp)
{
struct xmlelem *xelm;
int i;
if (xe == NULL)
return;
if (data_only) {
if (xe->xe_datalen)
fprintf(fp, "%*s\n",
(int)xe->xe_datalen, xe->xe_data);
TAILQ_FOREACH(xelm, &xe->xe_head, xe_entry)
xml_print(env, xelm, data_only, fp);
return;
}
/* Print XML header for the root node */
if (xe->xe_parent == NULL)
fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
fprintf(fp, "%*s<%s", xe->xe_depth * 2, "", xe->xe_tag);
for (i = 0; xe->xe_attr[i] != NULL; i += 2) {
fprintf(fp, " %s=\"%s\"",
xe->xe_attr[i], xe->xe_attr[i + 1]);
}
fprintf(fp, ">");
if (xe->xe_datalen)
fprintf(fp, "%*s",
(int)xe->xe_datalen, xe->xe_data);
if (!TAILQ_EMPTY(&xe->xe_head))
fprintf(fp, "\n");
TAILQ_FOREACH(xelm, &xe->xe_head, xe_entry)
xml_print(env, xelm, data_only, fp);
if (TAILQ_EMPTY(&xe->xe_head))
fprintf(fp, "</%s>\n", xe->xe_tag);
else
fprintf(fp, "%*s</%s>\n", xe->xe_depth * 2, "", xe->xe_tag);
}
/*
* Simple XML parser
*/
static void
xml_start_element(void *data, const char *el, const char **attr)
{
struct xml *env = data;
struct xmlelem *xe;
struct xmlhead *xh;
int i;
if ((xe = calloc(1, sizeof(*xe))) == NULL)
fatal("callac");
TAILQ_INIT(&xe->xe_head);
if (env->ox_cur == NULL)
xh = &env->ox_root;
else
xh = &env->ox_cur->xe_head;
xe->xe_parent = env->ox_cur;
xe->xe_depth = env->ox_depth;
if ((xe->xe_tag = strdup(el)) == NULL)
fatal("strdup");
TAILQ_INSERT_TAIL(xh, xe, xe_entry);
env->ox_cur = xe;
/* Copy attributes */
for (i = 0; attr[i] != NULL; i += 2)
;
xe->xe_nattr = i / 2;
if ((xe->xe_attr = calloc(i + 1, sizeof(char *))) == NULL)
fatal("calloc");
for (i = 0; attr[i] != NULL; i++) {
if ((xe->xe_attr[i] = strdup(attr[i])) == NULL)
fatal("strdup");
}
env->ox_depth++;
}
static void
xml_end_element(void *data, const char *el)
{
struct xml *env = data;
struct xmlelem *xe = env->ox_cur;
if (xe == NULL || strcmp(xe->xe_tag, el) != 0)
fatal("unexpected closing tag: %s <> %s", el, xe->xe_tag);
if (xe->xe_data == NULL)
xe->xe_data = strdup("");
env->ox_cur = xe->xe_parent;
env->ox_depth--;
}
static void
xml_char_data(void *data, const char *s, int len)
{
struct xml *env = data;
struct xmlelem *xe = env->ox_cur;
char *p;
int i;
int ok = 0;
off_t off = 0;
for (i = 0; i < len && s[i] != '\0'; i++) {
if (!isspace(s[i])) {
ok = 1;
break;
}
}
if (!ok)
return;
/* XXX there might be a better way to handle libexpat cdata */
if ((p = realloc(xe->xe_data, xe->xe_datalen + len + 2)) == NULL)
fatal("realloc");
if (xe->xe_datalen) {
p[xe->xe_datalen] = '\n';
off = 1;
}
memcpy(p + xe->xe_datalen + off, s, len);
p[xe->xe_datalen + off + len] = '\0';
xe->xe_data = p;
xe->xe_datalen += len + off;
env->ox_data = 1;
}
int
xml_init(struct xml *env)
{
XML_Parser parser;
memset(env, 0, sizeof(*env));
TAILQ_INIT(&env->ox_root);
if ((parser = XML_ParserCreate(NULL)) == NULL)
return (-1);
env->ox_parser = parser;
XML_SetUserData(parser, env);
XML_SetElementHandler(parser,
xml_start_element, xml_end_element);
XML_SetCharacterDataHandler(parser, xml_char_data);
return (0);
}
void
xml_free(struct xml *env)
{
if (env == NULL)
return;
if (env->ox_parser != NULL)
XML_ParserFree(env->ox_parser);
xml_delete(&env->ox_root);
memset(env, 0, sizeof(*env));
}
int
xml_parse_buffer(struct xml *env, char *xml, size_t xmllen)
{
XML_Parser parser = env->ox_parser;
if (XML_Parse(parser, xml, xmllen,
XML_TRUE) == XML_STATUS_ERROR)
return (-1);
XML_ParserFree(parser);
env->ox_parser = NULL;
if (TAILQ_EMPTY(&env->ox_root))
return (-1);
return (0);
}
int
xml_parse(struct xml *env, const char *file)
{
XML_Parser parser = env->ox_parser;
int fd;
void *xml;
ssize_t len;
if ((fd = open(file, O_RDONLY)) == -1)
fatal("open %s", file);
do {
if ((xml = XML_GetBuffer(parser, BUFSIZ)) == NULL)
fatalx("XML_GetBuffer");
if ((len = read(fd, xml, BUFSIZ)) <= 0)
break;
if (XML_ParseBuffer(parser, len, XML_FALSE) == XML_STATUS_ERROR)
fatalx("XML_ParseBuffer");
} while (len == BUFSIZ);
close(fd);
if (XML_Parse(parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
fatalx("XML_Parse");
XML_ParserFree(parser);
env->ox_parser = NULL;
return (0);
}

58
agent/xml.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef OVFXML_H
#define OVFXML_H
#include <sys/queue.h>
#include <stddef.h>
TAILQ_HEAD(xmlhead, xmlelem);
struct xmlelem {
char *xe_tag;
char **xe_attr;
unsigned int xe_nattr;
unsigned int xe_depth;
char *xe_data;
size_t xe_datalen;
struct xmlelem *xe_parent;
struct xmlhead xe_head;
TAILQ_ENTRY(xmlelem) xe_entry;
};
struct xml {
int ox_depth;
int ox_data;
struct xmlhead ox_root;
struct xmlelem *ox_cur;
struct xmlelem *ox_prev;
void *ox_parser;
};
int xml_init(struct xml *);
void xml_free(struct xml *);
void xml_add(struct xmlelem *, struct xmlelem *);
void xml_delete(struct xmlhead *);
struct xmlelem *xml_get(struct xmlhead *, const char *);
struct xmlelem *xml_findv(struct xmlhead *, const char **, int);
struct xmlelem *xml_findl(struct xmlhead *, const char *, ...);
void xml_print(struct xml *, struct xmlelem *, int, FILE *);
int xml_parse_buffer(struct xml *, char *, size_t);
int xml_parse(struct xml *, const char *);
#endif /* OVFXML_H */

3
cms/Makefile Normal file
View file

@ -0,0 +1,3 @@
SUBDIR= lib bin
.include <bsd.subdir.mk>

20
cms/Makefile.inc Normal file
View file

@ -0,0 +1,20 @@
.include <bsd.own.mk>
.include <bsd.obj.mk>
BINDIR?= /usr/local/bin
LIBCRYPTOSRC= ${BSDSRCDIR}/lib/libcrypto
CFLAGS+= -I${.CURDIR}
CFLAGS+= -I${.CURDIR}/../lib
CFLAGS+= -I${LIBCRYPTOSRC}/asn1
CFLAGS+= -I${LIBCRYPTOSRC}/evp
CFLAGS+= -Wall
.if exists(${.CURDIR}/../lib/${__objdir})
LDADD+= -L${.CURDIR}/../lib/${__objdir} -lcms
DPADD+= ${.CURDIR}/../lib/${__objdir}/libcms.a
.else
LDADD+= -L${.CURDIR}/../lib -lcms
DPADD+= ${.CURDIR}/../lib/libcms.a
.endif

9
cms/bin/Makefile Normal file
View file

@ -0,0 +1,9 @@
.PATH: ${BSDSRCDIR}/usr.bin/openssl
PROG= cms
SRCS= cms.c apps.c app_rand.c
LDADD+= -lcrypto
NOMAN= yes
.include <bsd.prog.mk>

203
cms/bin/app_rand.c Normal file
View file

@ -0,0 +1,203 @@
/* apps/app_rand.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#define NON_MAIN
#include "apps.h"
#undef NON_MAIN
#include <openssl/bio.h>
#include <openssl/rand.h>
static int seeded = 0;
int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn)
{
int consider_randfile = (file == NULL);
char buffer[200];
#ifdef OPENSSL_SYS_WINDOWS
RAND_screen();
#endif
if (file == NULL)
file = RAND_file_name(buffer, sizeof buffer);
if (file == NULL || !RAND_load_file(file, -1)) {
if (RAND_status() == 0) {
if (!dont_warn) {
BIO_printf(bio_e, "unable to load 'random state'\n");
BIO_printf(bio_e,
"This means that the random number generator has not been seeded\n");
BIO_printf(bio_e, "with much random data.\n");
if (consider_randfile) { /* explanation does not apply when a
* file is explicitly named */
BIO_printf(bio_e,
"Consider setting the RANDFILE environment variable to point at a file that\n");
BIO_printf(bio_e,
"'random' data can be kept in (the file will be overwritten).\n");
}
}
return 0;
}
}
seeded = 1;
return 1;
}
long app_RAND_load_files(char *name)
{
char *p, *n;
int last;
long tot = 0;
for (;;) {
last = 0;
for (p = name; ((*p != '\0') && (*p != ':')); p++) ;
if (*p == '\0')
last = 1;
*p = '\0';
n = name;
name = p + 1;
if (*n == '\0')
break;
tot += RAND_load_file(n, -1);
if (last)
break;
}
if (tot > 512)
app_RAND_allow_write_file();
return (tot);
}
int app_RAND_write_file(const char *file, BIO *bio_e)
{
char buffer[200];
if (!seeded)
/*
* If we did not manage to read the seed file, we should not write a
* low-entropy seed file back -- it would suppress a crucial warning
* the next time we want to use it.
*/
return 0;
if (file == NULL)
file = RAND_file_name(buffer, sizeof buffer);
if (file == NULL || !RAND_write_file(file)) {
BIO_printf(bio_e, "unable to write 'random state'\n");
return 0;
}
return 1;
}
void app_RAND_allow_write_file(void)
{
seeded = 1;
}

3251
cms/bin/apps.c Normal file

File diff suppressed because it is too large Load diff

385
cms/bin/apps.h Normal file
View file

@ -0,0 +1,385 @@
/* apps/apps.h */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#ifndef HEADER_APPS_H
# define HEADER_APPS_H
# include <openssl/bio.h>
# include <openssl/x509.h>
# include <openssl/lhash.h>
# include <openssl/conf.h>
# include <openssl/txt_db.h>
# ifndef OPENSSL_NO_ENGINE
# include <openssl/engine.h>
# endif
# ifndef OPENSSL_NO_OCSP
# include <openssl/ocsp.h>
# endif
# include <openssl/ossl_typ.h>
#include "libressl_apps.h"
int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
int app_RAND_write_file(const char *file, BIO *bio_e);
/*
* When `file' is NULL, use defaults. `bio_e' is for error messages.
*/
void app_RAND_allow_write_file(void);
long app_RAND_load_files(char *file); /* `file' is a list of files to read,
* separated by LIST_SEPARATOR_CHAR
* (see e_os.h). The string is
* destroyed! */
# ifndef MONOLITH
# define MAIN(a,v) main(a,v)
# ifndef NON_MAIN
CONF *config = NULL;
BIO *bio_err = NULL;
# else
extern CONF *config;
extern BIO *bio_err;
# endif
# else
# define MAIN(a,v) PROG(a,v)
extern CONF *config;
extern char *default_config_file;
extern BIO *bio_err;
# endif
# ifndef OPENSSL_SYS_NETWARE
# include <signal.h>
# endif
# ifdef SIGPIPE
# define do_pipe_sig() signal(SIGPIPE,SIG_IGN)
# else
# define do_pipe_sig()
# endif
# ifdef OPENSSL_NO_COMP
# define zlib_cleanup()
# else
# define zlib_cleanup() COMP_zlib_cleanup()
# endif
# if defined(MONOLITH) && !defined(OPENSSL_C)
# define apps_startup() \
do_pipe_sig()
# define apps_shutdown()
# else
# ifndef OPENSSL_NO_ENGINE
# define apps_startup() \
do { do_pipe_sig(); CRYPTO_malloc_init(); \
ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); \
ENGINE_load_builtin_engines(); setup_ui_method(); } while(0)
# define apps_shutdown() \
do { CONF_modules_unload(1); destroy_ui_method(); \
OBJ_cleanup(); EVP_cleanup(); ENGINE_cleanup(); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \
RAND_cleanup(); \
ERR_free_strings(); zlib_cleanup();} while(0)
# else
# define apps_startup() \
do { do_pipe_sig(); CRYPTO_malloc_init(); \
ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); \
setup_ui_method(); } while(0)
# define apps_shutdown() \
do { CONF_modules_unload(1); destroy_ui_method(); \
OBJ_cleanup(); EVP_cleanup(); \
CRYPTO_cleanup_all_ex_data(); ERR_remove_thread_state(NULL); \
RAND_cleanup(); \
ERR_free_strings(); zlib_cleanup(); } while(0)
# endif
# endif
# if defined(OPENSSL_SYSNAME_WIN32) || defined(OPENSSL_SYSNAME_WINCE)
# define openssl_fdset(a,b) FD_SET((unsigned int)a, b)
# else
# define openssl_fdset(a,b) FD_SET(a, b)
# endif
typedef struct args_st {
char **data;
int count;
} ARGS;
# define PW_MIN_LENGTH 4
typedef struct pw_cb_data {
const void *password;
const char *prompt_info;
} PW_CB_DATA;
int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data);
int setup_ui_method(void);
void destroy_ui_method(void);
int should_retry(int i);
int args_from_file(char *file, int *argc, char **argv[]);
int str2fmt(char *s);
void program_name(char *in, char *out, int size);
int chopup_args(ARGS *arg, char *buf, int *argc, char **argv[]);
# ifdef HEADER_X509_H
int dump_cert_text(BIO *out, X509 *x);
void print_name(BIO *out, const char *title, X509_NAME *nm,
unsigned long lflags);
# endif
int set_cert_ex(unsigned long *flags, const char *arg);
int set_name_ex(unsigned long *flags, const char *arg);
int set_ext_copy(int *copy_type, const char *arg);
int copy_extensions(X509 *x, X509_REQ *req, int copy_type);
int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2);
int add_oid_section(BIO *err, CONF *conf);
X509 *load_cert(BIO *err, const char *file, int format,
const char *pass, ENGINE *e, const char *cert_descrip);
X509_CRL *load_crl(const char *infile, int format);
int load_cert_crl_http(const char *url, BIO *err,
X509 **pcert, X509_CRL **pcrl);
EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
const char *pass, ENGINE *e, const char *key_descrip);
EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
const char *pass, ENGINE *e, const char *key_descrip);
STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
const char *pass, ENGINE *e,
const char *cert_descrip);
STACK_OF(X509_CRL) *load_crls(BIO *err, const char *file, int format,
const char *pass, ENGINE *e,
const char *cert_descrip);
X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
# ifndef OPENSSL_NO_ENGINE
ENGINE *setup_engine(BIO *err, const char *engine, int debug);
# endif
# ifndef OPENSSL_NO_OCSP
OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
const char *host, const char *path,
const char *port, int use_ssl,
const STACK_OF(CONF_VALUE) *headers,
int req_timeout);
# endif
int load_config(BIO *err, CONF *cnf);
char *make_config_name(void);
/* Functions defined in ca.c and also used in ocsp.c */
int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold,
ASN1_GENERALIZEDTIME **pinvtm, const char *str);
# define DB_type 0
# define DB_exp_date 1
# define DB_rev_date 2
# define DB_serial 3 /* index - unique */
# define DB_file 4
# define DB_name 5 /* index - unique when active and not
* disabled */
# define DB_NUMBER 6
# define DB_TYPE_REV 'R'
# define DB_TYPE_EXP 'E'
# define DB_TYPE_VAL 'V'
typedef struct db_attr_st {
int unique_subject;
} DB_ATTR;
typedef struct ca_db_st {
DB_ATTR attributes;
TXT_DB *db;
} CA_DB;
BIGNUM *load_serial(char *serialfile, int create, ASN1_INTEGER **retai);
int save_serial(char *serialfile, char *suffix, BIGNUM *serial,
ASN1_INTEGER **retai);
int rotate_serial(char *serialfile, char *new_suffix, char *old_suffix);
int rand_serial(BIGNUM *b, ASN1_INTEGER *ai);
CA_DB *load_index(char *dbfile, DB_ATTR *dbattr);
int index_index(CA_DB *db);
int save_index(const char *dbfile, const char *suffix, CA_DB *db);
int rotate_index(const char *dbfile, const char *new_suffix,
const char *old_suffix);
void free_index(CA_DB *db);
# define index_name_cmp_noconst(a, b) \
index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \
(const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b))
int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b);
int parse_yesno(const char *str, int def);
X509_NAME *parse_name(char *str, long chtype, int multirdn);
int args_verify(char ***pargs, int *pargc,
int *badarg, BIO *err, X509_VERIFY_PARAM **pm);
void policies_print(BIO *out, X509_STORE_CTX *ctx);
int bio_to_mem(unsigned char **out, int maxlen, BIO *in);
int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value);
int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
const char *algname, ENGINE *e, int do_param);
int do_X509_sign(BIO *err, X509 *x, EVP_PKEY *pkey, const EVP_MD *md,
STACK_OF(OPENSSL_STRING) *sigopts);
int do_X509_REQ_sign(BIO *err, X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md,
STACK_OF(OPENSSL_STRING) *sigopts);
int do_X509_CRL_sign(BIO *err, X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md,
STACK_OF(OPENSSL_STRING) *sigopts);
# ifndef OPENSSL_NO_PSK
extern char *psk_key;
# endif
# ifndef OPENSSL_NO_JPAKE
void jpake_client_auth(BIO *out, BIO *conn, const char *secret);
void jpake_server_auth(BIO *out, BIO *conn, const char *secret);
# endif
# ifndef OPENSSL_NO_TLSEXT
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
# endif /* ndef OPENSSL_NO_TLSEXT */
void store_setup_crl_download(X509_STORE *st);
# define FORMAT_UNDEF 0
# define FORMAT_ASN1 1
# define FORMAT_TEXT 2
# define FORMAT_PEM 3
# define FORMAT_NETSCAPE 4
# define FORMAT_PKCS12 5
# define FORMAT_SMIME 6
# define FORMAT_ENGINE 7
# define FORMAT_IISSGC 8 /* XXX this stupid macro helps us to avoid
* adding yet another param to load_*key() */
# define FORMAT_PEMRSA 9 /* PEM RSAPubicKey format */
# define FORMAT_ASN1RSA 10 /* DER RSAPubicKey format */
# define FORMAT_MSBLOB 11 /* MS Key blob format */
# define FORMAT_PVK 12 /* MS PVK file format */
# define FORMAT_HTTP 13 /* Download using HTTP */
# define EXT_COPY_NONE 0
# define EXT_COPY_ADD 1
# define EXT_COPY_ALL 2
# define NETSCAPE_CERT_HDR "certificate"
# define APP_PASS_LEN 1024
# define SERIAL_RAND_BITS 64
int app_isdir(const char *);
int fileno_stdin(void);
int fileno_stdout(void);
int raw_read_stdin(void *, int);
int raw_write_stdout(const void *, int);
# define TM_START 0
# define TM_STOP 1
double app_tminterval(int stop, int usertime);
# define OPENSSL_NO_SSL_INTERN
#endif

1354
cms/bin/cms.c Normal file

File diff suppressed because it is too large Load diff

19
cms/bin/libressl_apps.h Normal file
View file

@ -0,0 +1,19 @@
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/asn1.h>
#ifdef USE_OPENSSL
#include <openssl/cms.h>
#else
#include "cms.h"
#include "cms_lcl.h"
#endif
#include "apps.h"
#include <unistd.h>
#define OPENSSL_CONF "openssl.cnf"
#define OPENSSL_NO_ENGINE
#define MS_STATIC static
int cms_main(int argc, char **argv);

19
cms/lib/Makefile Normal file
View file

@ -0,0 +1,19 @@
LIB= cms
SRCS+= cms_asn1.c cms_dd.c cms_err.c cms_kari.c cms_sd.c
SRCS+= cms_att.c cms_enc.c cms_ess.c cms_lib.c cms_smime.c
SRCS+= cms_cd.c cms_env.c cms_io.c cms_pwri.c
SRCS+= libressl_pkey.c libressl_stubs.c
DEBUGLIBS= no
NOPROFILE= yes
NOPIC= yes
LDADD+= -lcrypto
NOMAN= yes
install:
@echo -n
.include <bsd.own.mk>
.include <bsd.lib.mk>

155
cms/lib/asn1_locl.h Normal file
View file

@ -0,0 +1,155 @@
/* $OpenBSD: asn1_locl.h,v 1.8 2016/12/21 15:49:29 jsing Exp $ */
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project 2006.
*/
/* ====================================================================
* Copyright (c) 2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
__BEGIN_HIDDEN_DECLS
/* Internal ASN1 structures and functions: not for application use */
/* ASN1 print context structure */
struct asn1_pctx_st {
unsigned long flags;
unsigned long nm_flags;
unsigned long cert_flags;
unsigned long oid_flags;
unsigned long str_flags;
} /* ASN1_PCTX */;
/* ASN1 public key method structure */
struct evp_pkey_asn1_method_st {
int pkey_id;
int pkey_base_id;
unsigned long pkey_flags;
char *pem_str;
char *info;
int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub);
int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk);
int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx);
int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf);
int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk);
int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx);
int (*pkey_size)(const EVP_PKEY *pk);
int (*pkey_bits)(const EVP_PKEY *pk);
int (*param_decode)(EVP_PKEY *pkey, const unsigned char **pder,
int derlen);
int (*param_encode)(const EVP_PKEY *pkey, unsigned char **pder);
int (*param_missing)(const EVP_PKEY *pk);
int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from);
int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx);
int (*sig_print)(BIO *out, const X509_ALGOR *sigalg,
const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx);
void (*pkey_free)(EVP_PKEY *pkey);
int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2);
/* Legacy functions for old PEM */
int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder,
int derlen);
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
/* Custom ASN1 signature verification */
int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey);
int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
X509_ALGOR *alg1, X509_ALGOR *alg2, ASN1_BIT_STRING *sig);
} /* EVP_PKEY_ASN1_METHOD */;
/* Method to handle CRL access.
* In general a CRL could be very large (several Mb) and can consume large
* amounts of resources if stored in memory by multiple processes.
* This method allows general CRL operations to be redirected to more
* efficient callbacks: for example a CRL entry database.
*/
#define X509_CRL_METHOD_DYNAMIC 1
struct x509_crl_method_st {
int flags;
int (*crl_init)(X509_CRL *crl);
int (*crl_free)(X509_CRL *crl);
int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
ASN1_INTEGER *ser, X509_NAME *issuer);
int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
};
/*
* Unicode codepoint constants
*/
#define UNICODE_MAX 0x10FFFF
#define UNICODE_SURROGATE_MIN 0x00D800
#define UNICODE_SURROGATE_MAX 0x00DFFF
#define UNICODE_IS_SURROGATE(x) \
((x) >= UNICODE_SURROGATE_MIN && (x) <= UNICODE_SURROGATE_MAX)
int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
int UTF8_putc(unsigned char *str, int len, unsigned long value);
__END_HIDDEN_DECLS

579
cms/lib/asn1_mac.h Normal file
View file

@ -0,0 +1,579 @@
/* crypto/asn1/asn1_mac.h */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
#ifndef HEADER_ASN1_MAC_H
# define HEADER_ASN1_MAC_H
# include <openssl/asn1.h>
#ifdef __cplusplus
extern "C" {
#endif
# ifndef ASN1_MAC_ERR_LIB
# define ASN1_MAC_ERR_LIB ERR_LIB_ASN1
# endif
# define ASN1_MAC_H_err(f,r,line) \
ERR_PUT_error(ASN1_MAC_ERR_LIB,(f),(r),__FILE__,(line))
# define M_ASN1_D2I_vars(a,type,func) \
ASN1_const_CTX c; \
type ret=NULL; \
\
c.pp=(const unsigned char **)pp; \
c.q= *(const unsigned char **)pp; \
c.error=ERR_R_NESTED_ASN1_ERROR; \
if ((a == NULL) || ((*a) == NULL)) \
{ if ((ret=(type)func()) == NULL) \
{ c.line=__LINE__; goto err; } } \
else ret=(*a);
# define M_ASN1_D2I_Init() \
c.p= *(const unsigned char **)pp; \
c.max=(length == 0)?0:(c.p+length);
# define M_ASN1_D2I_Finish_2(a) \
if (!asn1_const_Finish(&c)) \
{ c.line=__LINE__; goto err; } \
*(const unsigned char **)pp=c.p; \
if (a != NULL) (*a)=ret; \
return(ret);
# define M_ASN1_D2I_Finish(a,func,e) \
M_ASN1_D2I_Finish_2(a); \
err:\
ASN1_MAC_H_err((e),c.error,c.line); \
asn1_add_error(*(const unsigned char **)pp,(int)(c.q- *pp)); \
if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
return(NULL)
# define M_ASN1_D2I_start_sequence() \
if (!asn1_GetSequence(&c,&length)) \
{ c.line=__LINE__; goto err; }
/* Begin reading ASN1 without a surrounding sequence */
# define M_ASN1_D2I_begin() \
c.slen = length;
/* End reading ASN1 with no check on length */
# define M_ASN1_D2I_Finish_nolen(a, func, e) \
*pp=c.p; \
if (a != NULL) (*a)=ret; \
return(ret); \
err:\
ASN1_MAC_H_err((e),c.error,c.line); \
asn1_add_error(*pp,(int)(c.q- *pp)); \
if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
return(NULL)
# define M_ASN1_D2I_end_sequence() \
(((c.inf&1) == 0)?(c.slen <= 0): \
(c.eos=ASN1_const_check_infinite_end(&c.p,c.slen)))
/* Don't use this with d2i_ASN1_BOOLEAN() */
# define M_ASN1_D2I_get(b, func) \
c.q=c.p; \
if (func(&(b),&c.p,c.slen) == NULL) \
{c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
/* Don't use this with d2i_ASN1_BOOLEAN() */
# define M_ASN1_D2I_get_x(type,b,func) \
c.q=c.p; \
if (((D2I_OF(type))func)(&(b),&c.p,c.slen) == NULL) \
{c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
/* use this instead () */
# define M_ASN1_D2I_get_int(b,func) \
c.q=c.p; \
if (func(&(b),&c.p,c.slen) < 0) \
{c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
# define M_ASN1_D2I_get_opt(b,func,type) \
if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
== (V_ASN1_UNIVERSAL|(type)))) \
{ \
M_ASN1_D2I_get(b,func); \
}
# define M_ASN1_D2I_get_int_opt(b,func,type) \
if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
== (V_ASN1_UNIVERSAL|(type)))) \
{ \
M_ASN1_D2I_get_int(b,func); \
}
# define M_ASN1_D2I_get_imp(b,func, type) \
M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \
c.q=c.p; \
if (func(&(b),&c.p,c.slen) == NULL) \
{c.line=__LINE__; M_ASN1_next_prev = _tmp; goto err; } \
c.slen-=(c.p-c.q);\
M_ASN1_next_prev=_tmp;
# define M_ASN1_D2I_get_IMP_opt(b,func,tag,type) \
if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) == \
(V_ASN1_CONTEXT_SPECIFIC|(tag)))) \
{ \
unsigned char _tmp = M_ASN1_next; \
M_ASN1_D2I_get_imp(b,func, type);\
}
# define M_ASN1_D2I_get_set(r,func,free_func) \
M_ASN1_D2I_get_imp_set(r,func,free_func, \
V_ASN1_SET,V_ASN1_UNIVERSAL);
# define M_ASN1_D2I_get_set_type(type,r,func,free_func) \
M_ASN1_D2I_get_imp_set_type(type,r,func,free_func, \
V_ASN1_SET,V_ASN1_UNIVERSAL);
# define M_ASN1_D2I_get_set_opt(r,func,free_func) \
if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
{ M_ASN1_D2I_get_set(r,func,free_func); }
# define M_ASN1_D2I_get_set_opt_type(type,r,func,free_func) \
if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
{ M_ASN1_D2I_get_set_type(type,r,func,free_func); }
# define M_ASN1_I2D_len_SET_opt(a,f) \
if ((a != NULL) && (sk_num(a) != 0)) \
M_ASN1_I2D_len_SET(a,f);
# define M_ASN1_I2D_put_SET_opt(a,f) \
if ((a != NULL) && (sk_num(a) != 0)) \
M_ASN1_I2D_put_SET(a,f);
# define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
if ((a != NULL) && (sk_num(a) != 0)) \
M_ASN1_I2D_put_SEQUENCE(a,f);
# define M_ASN1_I2D_put_SEQUENCE_opt_type(type,a,f) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
M_ASN1_I2D_put_SEQUENCE_type(type,a,f);
# define M_ASN1_D2I_get_IMP_set_opt(b,func,free_func,tag) \
if ((c.slen != 0) && \
(M_ASN1_next == \
(V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
{ \
M_ASN1_D2I_get_imp_set(b,func,free_func,\
tag,V_ASN1_CONTEXT_SPECIFIC); \
}
# define M_ASN1_D2I_get_IMP_set_opt_type(type,b,func,free_func,tag) \
if ((c.slen != 0) && \
(M_ASN1_next == \
(V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
{ \
M_ASN1_D2I_get_imp_set_type(type,b,func,free_func,\
tag,V_ASN1_CONTEXT_SPECIFIC); \
}
# define M_ASN1_D2I_get_seq(r,func,free_func) \
M_ASN1_D2I_get_imp_set(r,func,free_func,\
V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL);
# define M_ASN1_D2I_get_seq_type(type,r,func,free_func) \
M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
# define M_ASN1_D2I_get_seq_opt(r,func,free_func) \
if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
{ M_ASN1_D2I_get_seq(r,func,free_func); }
# define M_ASN1_D2I_get_seq_opt_type(type,r,func,free_func) \
if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
{ M_ASN1_D2I_get_seq_type(type,r,func,free_func); }
# define M_ASN1_D2I_get_IMP_set(r,func,free_func,x) \
M_ASN1_D2I_get_imp_set(r,func,free_func,\
x,V_ASN1_CONTEXT_SPECIFIC);
# define M_ASN1_D2I_get_IMP_set_type(type,r,func,free_func,x) \
M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
x,V_ASN1_CONTEXT_SPECIFIC);
# define M_ASN1_D2I_get_imp_set(r,func,free_func,a,b) \
c.q=c.p; \
if (d2i_ASN1_SET(&(r),&c.p,c.slen,(char *(*)())func,\
(void (*)())free_func,a,b) == NULL) \
{ c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
# define M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,a,b) \
c.q=c.p; \
if (d2i_ASN1_SET_OF_##type(&(r),&c.p,c.slen,func,\
free_func,a,b) == NULL) \
{ c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
# define M_ASN1_D2I_get_set_strings(r,func,a,b) \
c.q=c.p; \
if (d2i_ASN1_STRING_SET(&(r),&c.p,c.slen,a,b) == NULL) \
{ c.line=__LINE__; goto err; } \
c.slen-=(c.p-c.q);
# define M_ASN1_D2I_get_EXP_opt(r,func,tag) \
if ((c.slen != 0L) && (M_ASN1_next == \
(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
{ \
int Tinf,Ttag,Tclass; \
long Tlen; \
\
c.q=c.p; \
Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
if (Tinf & 0x80) \
{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
Tlen = c.slen - (c.p - c.q) - 2; \
if (func(&(r),&c.p,Tlen) == NULL) \
{ c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
Tlen = c.slen - (c.p - c.q); \
if(!ASN1_const_check_infinite_end(&c.p, Tlen)) \
{ c.error=ERR_R_MISSING_ASN1_EOS; \
c.line=__LINE__; goto err; } \
}\
c.slen-=(c.p-c.q); \
}
# define M_ASN1_D2I_get_EXP_set_opt(r,func,free_func,tag,b) \
if ((c.slen != 0) && (M_ASN1_next == \
(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
{ \
int Tinf,Ttag,Tclass; \
long Tlen; \
\
c.q=c.p; \
Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
if (Tinf & 0x80) \
{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
Tlen = c.slen - (c.p - c.q) - 2; \
if (d2i_ASN1_SET(&(r),&c.p,Tlen,(char *(*)())func, \
(void (*)())free_func, \
b,V_ASN1_UNIVERSAL) == NULL) \
{ c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
Tlen = c.slen - (c.p - c.q); \
if(!ASN1_check_infinite_end(&c.p, Tlen)) \
{ c.error=ERR_R_MISSING_ASN1_EOS; \
c.line=__LINE__; goto err; } \
}\
c.slen-=(c.p-c.q); \
}
# define M_ASN1_D2I_get_EXP_set_opt_type(type,r,func,free_func,tag,b) \
if ((c.slen != 0) && (M_ASN1_next == \
(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
{ \
int Tinf,Ttag,Tclass; \
long Tlen; \
\
c.q=c.p; \
Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
if (Tinf & 0x80) \
{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
Tlen = c.slen - (c.p - c.q) - 2; \
if (d2i_ASN1_SET_OF_##type(&(r),&c.p,Tlen,func, \
free_func,b,V_ASN1_UNIVERSAL) == NULL) \
{ c.line=__LINE__; goto err; } \
if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
Tlen = c.slen - (c.p - c.q); \
if(!ASN1_check_infinite_end(&c.p, Tlen)) \
{ c.error=ERR_R_MISSING_ASN1_EOS; \
c.line=__LINE__; goto err; } \
}\
c.slen-=(c.p-c.q); \
}
/* New macros */
# define M_ASN1_New_Malloc(ret,type) \
if ((ret=(type *)OPENSSL_malloc(sizeof(type))) == NULL) \
{ c.line=__LINE__; goto err2; }
# define M_ASN1_New(arg,func) \
if (((arg)=func()) == NULL) return(NULL)
# define M_ASN1_New_Error(a) \
/*- err: ASN1_MAC_H_err((a),ERR_R_NESTED_ASN1_ERROR,c.line); \
return(NULL);*/ \
err2: ASN1_MAC_H_err((a),ERR_R_MALLOC_FAILURE,c.line); \
return(NULL)
/*
* BIG UGLY WARNING! This is so damn ugly I wanna puke. Unfortunately, some
* macros that use ASN1_const_CTX still insist on writing in the input
* stream. ARGH! ARGH! ARGH! Let's get rid of this macro package. Please? --
* Richard Levitte
*/
# define M_ASN1_next (*((unsigned char *)(c.p)))
# define M_ASN1_next_prev (*((unsigned char *)(c.q)))
/*************************************************/
# define M_ASN1_I2D_vars(a) int r=0,ret=0; \
unsigned char *p; \
if (a == NULL) return(0)
/* Length Macros */
# define M_ASN1_I2D_len(a,f) ret+=f(a,NULL)
# define M_ASN1_I2D_len_IMP_opt(a,f) if (a != NULL) M_ASN1_I2D_len(a,f)
# define M_ASN1_I2D_len_SET(a,f) \
ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
# define M_ASN1_I2D_len_SET_type(type,a,f) \
ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SET, \
V_ASN1_UNIVERSAL,IS_SET);
# define M_ASN1_I2D_len_SEQUENCE(a,f) \
ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
IS_SEQUENCE);
# define M_ASN1_I2D_len_SEQUENCE_type(type,a,f) \
ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SEQUENCE, \
V_ASN1_UNIVERSAL,IS_SEQUENCE)
# define M_ASN1_I2D_len_SEQUENCE_opt(a,f) \
if ((a != NULL) && (sk_num(a) != 0)) \
M_ASN1_I2D_len_SEQUENCE(a,f);
# define M_ASN1_I2D_len_SEQUENCE_opt_type(type,a,f) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
M_ASN1_I2D_len_SEQUENCE_type(type,a,f);
# define M_ASN1_I2D_len_IMP_SET(a,f,x) \
ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET);
# define M_ASN1_I2D_len_IMP_SET_type(type,a,f,x) \
ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
V_ASN1_CONTEXT_SPECIFIC,IS_SET);
# define M_ASN1_I2D_len_IMP_SET_opt(a,f,x) \
if ((a != NULL) && (sk_num(a) != 0)) \
ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
IS_SET);
# define M_ASN1_I2D_len_IMP_SET_opt_type(type,a,f,x) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
V_ASN1_CONTEXT_SPECIFIC,IS_SET);
# define M_ASN1_I2D_len_IMP_SEQUENCE(a,f,x) \
ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
IS_SEQUENCE);
# define M_ASN1_I2D_len_IMP_SEQUENCE_opt(a,f,x) \
if ((a != NULL) && (sk_num(a) != 0)) \
ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
IS_SEQUENCE);
# define M_ASN1_I2D_len_IMP_SEQUENCE_opt_type(type,a,f,x) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
V_ASN1_CONTEXT_SPECIFIC, \
IS_SEQUENCE);
# define M_ASN1_I2D_len_EXP_opt(a,f,mtag,v) \
if (a != NULL)\
{ \
v=f(a,NULL); \
ret+=ASN1_object_size(1,v,mtag); \
}
# define M_ASN1_I2D_len_EXP_SET_opt(a,f,mtag,tag,v) \
if ((a != NULL) && (sk_num(a) != 0))\
{ \
v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
ret+=ASN1_object_size(1,v,mtag); \
}
# define M_ASN1_I2D_len_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
if ((a != NULL) && (sk_num(a) != 0))\
{ \
v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL, \
IS_SEQUENCE); \
ret+=ASN1_object_size(1,v,mtag); \
}
# define M_ASN1_I2D_len_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
if ((a != NULL) && (sk_##type##_num(a) != 0))\
{ \
v=i2d_ASN1_SET_OF_##type(a,NULL,f,tag, \
V_ASN1_UNIVERSAL, \
IS_SEQUENCE); \
ret+=ASN1_object_size(1,v,mtag); \
}
/* Put Macros */
# define M_ASN1_I2D_put(a,f) f(a,&p)
# define M_ASN1_I2D_put_IMP_opt(a,f,t) \
if (a != NULL) \
{ \
unsigned char *q=p; \
f(a,&p); \
*q=(V_ASN1_CONTEXT_SPECIFIC|t|(*q&V_ASN1_CONSTRUCTED));\
}
# define M_ASN1_I2D_put_SET(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SET,\
V_ASN1_UNIVERSAL,IS_SET)
# define M_ASN1_I2D_put_SET_type(type,a,f) \
i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET)
# define M_ASN1_I2D_put_IMP_SET(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
V_ASN1_CONTEXT_SPECIFIC,IS_SET)
# define M_ASN1_I2D_put_IMP_SET_type(type,a,f,x) \
i2d_ASN1_SET_OF_##type(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET)
# define M_ASN1_I2D_put_IMP_SEQUENCE(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
V_ASN1_CONTEXT_SPECIFIC,IS_SEQUENCE)
# define M_ASN1_I2D_put_SEQUENCE(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SEQUENCE,\
V_ASN1_UNIVERSAL,IS_SEQUENCE)
# define M_ASN1_I2D_put_SEQUENCE_type(type,a,f) \
i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
IS_SEQUENCE)
# define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
if ((a != NULL) && (sk_num(a) != 0)) \
M_ASN1_I2D_put_SEQUENCE(a,f);
# define M_ASN1_I2D_put_IMP_SET_opt(a,f,x) \
if ((a != NULL) && (sk_num(a) != 0)) \
{ i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
IS_SET); }
# define M_ASN1_I2D_put_IMP_SET_opt_type(type,a,f,x) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
{ i2d_ASN1_SET_OF_##type(a,&p,f,x, \
V_ASN1_CONTEXT_SPECIFIC, \
IS_SET); }
# define M_ASN1_I2D_put_IMP_SEQUENCE_opt(a,f,x) \
if ((a != NULL) && (sk_num(a) != 0)) \
{ i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
IS_SEQUENCE); }
# define M_ASN1_I2D_put_IMP_SEQUENCE_opt_type(type,a,f,x) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
{ i2d_ASN1_SET_OF_##type(a,&p,f,x, \
V_ASN1_CONTEXT_SPECIFIC, \
IS_SEQUENCE); }
# define M_ASN1_I2D_put_EXP_opt(a,f,tag,v) \
if (a != NULL) \
{ \
ASN1_put_object(&p,1,v,tag,V_ASN1_CONTEXT_SPECIFIC); \
f(a,&p); \
}
# define M_ASN1_I2D_put_EXP_SET_opt(a,f,mtag,tag,v) \
if ((a != NULL) && (sk_num(a) != 0)) \
{ \
ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
}
# define M_ASN1_I2D_put_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
if ((a != NULL) && (sk_num(a) != 0)) \
{ \
ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SEQUENCE); \
}
# define M_ASN1_I2D_put_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
if ((a != NULL) && (sk_##type##_num(a) != 0)) \
{ \
ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
i2d_ASN1_SET_OF_##type(a,&p,f,tag,V_ASN1_UNIVERSAL, \
IS_SEQUENCE); \
}
# define M_ASN1_I2D_seq_total() \
r=ASN1_object_size(1,ret,V_ASN1_SEQUENCE); \
if (pp == NULL) return(r); \
p= *pp; \
ASN1_put_object(&p,1,ret,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
# define M_ASN1_I2D_INF_seq_start(tag,ctx) \
*(p++)=(V_ASN1_CONSTRUCTED|(tag)|(ctx)); \
*(p++)=0x80
# define M_ASN1_I2D_INF_seq_end() *(p++)=0x00; *(p++)=0x00
# define M_ASN1_I2D_finish() *pp=p; \
return(r);
int asn1_GetSequence(ASN1_const_CTX *c, long *length);
void asn1_add_error(const unsigned char *address, int offset);
#ifdef __cplusplus
}
#endif
#endif

973
cms/lib/asn1t.h Normal file
View file

@ -0,0 +1,973 @@
/* asn1t.h */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
* 2000.
*/
/* ====================================================================
* Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
#ifndef HEADER_ASN1T_H
# define HEADER_ASN1T_H
# include <stddef.h>
# include <openssl/e_os2.h>
# include <openssl/asn1.h>
# ifdef OPENSSL_BUILD_SHLIBCRYPTO
# undef OPENSSL_EXTERN
# define OPENSSL_EXTERN OPENSSL_EXPORT
# endif
/* ASN1 template defines, structures and functions */
#ifdef __cplusplus
extern "C" {
#endif
# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
# define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr))
/* Macros for start and end of ASN1_ITEM definition */
# define ASN1_ITEM_start(itname) \
OPENSSL_GLOBAL const ASN1_ITEM itname##_it = {
# define ASN1_ITEM_end(itname) \
};
# else
/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
# define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr()))
/* Macros for start and end of ASN1_ITEM definition */
# define ASN1_ITEM_start(itname) \
const ASN1_ITEM * itname##_it(void) \
{ \
static const ASN1_ITEM local_it = {
# define ASN1_ITEM_end(itname) \
}; \
return &local_it; \
}
# endif
/* Macros to aid ASN1 template writing */
# define ASN1_ITEM_TEMPLATE(tname) \
static const ASN1_TEMPLATE tname##_item_tt
# define ASN1_ITEM_TEMPLATE_END(tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_PRIMITIVE,\
-1,\
&tname##_item_tt,\
0,\
NULL,\
0,\
#tname \
ASN1_ITEM_end(tname)
/* This is a ASN1 type which just embeds a template */
/*-
* This pair helps declare a SEQUENCE. We can do:
*
* ASN1_SEQUENCE(stname) = {
* ... SEQUENCE components ...
* } ASN1_SEQUENCE_END(stname)
*
* This will produce an ASN1_ITEM called stname_it
* for a structure called stname.
*
* If you want the same structure but a different
* name then use:
*
* ASN1_SEQUENCE(itname) = {
* ... SEQUENCE components ...
* } ASN1_SEQUENCE_END_name(stname, itname)
*
* This will create an item called itname_it using
* a structure called stname.
*/
# define ASN1_SEQUENCE(tname) \
static const ASN1_TEMPLATE tname##_seq_tt[]
# define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
# define ASN1_SEQUENCE_END_name(stname, tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_SEQUENCE,\
V_ASN1_SEQUENCE,\
tname##_seq_tt,\
sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
NULL,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
# define ASN1_NDEF_SEQUENCE(tname) \
ASN1_SEQUENCE(tname)
# define ASN1_NDEF_SEQUENCE_cb(tname, cb) \
ASN1_SEQUENCE_cb(tname, cb)
# define ASN1_SEQUENCE_cb(tname, cb) \
static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
ASN1_SEQUENCE(tname)
# define ASN1_BROKEN_SEQUENCE(tname) \
static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \
ASN1_SEQUENCE(tname)
# define ASN1_SEQUENCE_ref(tname, cb, lck) \
static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), lck, cb, 0}; \
ASN1_SEQUENCE(tname)
# define ASN1_SEQUENCE_enc(tname, enc, cb) \
static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \
ASN1_SEQUENCE(tname)
# define ASN1_NDEF_SEQUENCE_END(tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_NDEF_SEQUENCE,\
V_ASN1_SEQUENCE,\
tname##_seq_tt,\
sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
NULL,\
sizeof(tname),\
#tname \
ASN1_ITEM_end(tname)
# define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname)
# define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
# define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
# define ASN1_SEQUENCE_END_ref(stname, tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_SEQUENCE,\
V_ASN1_SEQUENCE,\
tname##_seq_tt,\
sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
&tname##_aux,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
# define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_NDEF_SEQUENCE,\
V_ASN1_SEQUENCE,\
tname##_seq_tt,\
sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
&tname##_aux,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
/*-
* This pair helps declare a CHOICE type. We can do:
*
* ASN1_CHOICE(chname) = {
* ... CHOICE options ...
* ASN1_CHOICE_END(chname)
*
* This will produce an ASN1_ITEM called chname_it
* for a structure called chname. The structure
* definition must look like this:
* typedef struct {
* int type;
* union {
* ASN1_SOMETHING *opt1;
* ASN1_SOMEOTHER *opt2;
* } value;
* } chname;
*
* the name of the selector must be 'type'.
* to use an alternative selector name use the
* ASN1_CHOICE_END_selector() version.
*/
# define ASN1_CHOICE(tname) \
static const ASN1_TEMPLATE tname##_ch_tt[]
# define ASN1_CHOICE_cb(tname, cb) \
static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
ASN1_CHOICE(tname)
# define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname)
# define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type)
# define ASN1_CHOICE_END_selector(stname, tname, selname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_CHOICE,\
offsetof(stname,selname) ,\
tname##_ch_tt,\
sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
NULL,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
# define ASN1_CHOICE_END_cb(stname, tname, selname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_CHOICE,\
offsetof(stname,selname) ,\
tname##_ch_tt,\
sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
&tname##_aux,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
/* This helps with the template wrapper form of ASN1_ITEM */
# define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \
(flags), (tag), 0,\
#name, ASN1_ITEM_ref(type) }
/* These help with SEQUENCE or CHOICE components */
/* used to declare other types */
# define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
(flags), (tag), offsetof(stname, field),\
#field, ASN1_ITEM_ref(type) }
/* used when the structure is combined with the parent */
# define ASN1_EX_COMBINE(flags, tag, type) { \
(flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) }
/* implicit and explicit helper macros */
# define ASN1_IMP_EX(stname, field, type, tag, ex) \
ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type)
# define ASN1_EXP_EX(stname, field, type, tag, ex) \
ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type)
/* Any defined by macros: the field used is in the table itself */
# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
# define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
# define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
# else
# define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb }
# define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb }
# endif
/* Plain simple type */
# define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
/* OPTIONAL simple type */
# define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
/* IMPLICIT tagged simple type */
# define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0)
/* IMPLICIT tagged OPTIONAL simple type */
# define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
/* Same as above but EXPLICIT */
# define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0)
# define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
/* SEQUENCE OF type */
# define ASN1_SEQUENCE_OF(stname, field, type) \
ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type)
/* OPTIONAL SEQUENCE OF */
# define ASN1_SEQUENCE_OF_OPT(stname, field, type) \
ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
/* Same as above but for SET OF */
# define ASN1_SET_OF(stname, field, type) \
ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type)
# define ASN1_SET_OF_OPT(stname, field, type) \
ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */
# define ASN1_IMP_SET_OF(stname, field, type, tag) \
ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
# define ASN1_EXP_SET_OF(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
# define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \
ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
# define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
# define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \
ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
# define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
# define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
# define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
/* EXPLICIT using indefinite length constructed form */
# define ASN1_NDEF_EXP(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF)
/* EXPLICIT OPTIONAL using indefinite length constructed form */
# define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF)
/* Macros for the ASN1_ADB structure */
# define ASN1_ADB(name) \
static const ASN1_ADB_TABLE name##_adbtbl[]
# ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
# define ASN1_ADB_END(name, flags, field, app_table, def, none) \
;\
static const ASN1_ADB name##_adb = {\
flags,\
offsetof(name, field),\
app_table,\
name##_adbtbl,\
sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
def,\
none\
}
# else
# define ASN1_ADB_END(name, flags, field, app_table, def, none) \
;\
static const ASN1_ITEM *name##_adb(void) \
{ \
static const ASN1_ADB internal_adb = \
{\
flags,\
offsetof(name, field),\
app_table,\
name##_adbtbl,\
sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
def,\
none\
}; \
return (const ASN1_ITEM *) &internal_adb; \
} \
void dummy_function(void)
# endif
# define ADB_ENTRY(val, template) {val, template}
# define ASN1_ADB_TEMPLATE(name) \
static const ASN1_TEMPLATE name##_tt
/*
* This is the ASN1 template structure that defines a wrapper round the
* actual type. It determines the actual position of the field in the value
* structure, various flags such as OPTIONAL and the field name.
*/
struct ASN1_TEMPLATE_st {
unsigned long flags; /* Various flags */
long tag; /* tag, not used if no tagging */
unsigned long offset; /* Offset of this field in structure */
# ifndef NO_ASN1_FIELD_NAMES
const char *field_name; /* Field name */
# endif
ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
};
/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */
# define ASN1_TEMPLATE_item(t) (t->item_ptr)
# define ASN1_TEMPLATE_adb(t) (t->item_ptr)
typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE;
typedef struct ASN1_ADB_st ASN1_ADB;
struct ASN1_ADB_st {
unsigned long flags; /* Various flags */
unsigned long offset; /* Offset of selector field */
STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */
const ASN1_ADB_TABLE *tbl; /* Table of possible types */
long tblcount; /* Number of entries in tbl */
const ASN1_TEMPLATE *default_tt; /* Type to use if no match */
const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */
};
struct ASN1_ADB_TABLE_st {
long value; /* NID for an object or value for an int */
const ASN1_TEMPLATE tt; /* item for this value */
};
/* template flags */
/* Field is optional */
# define ASN1_TFLG_OPTIONAL (0x1)
/* Field is a SET OF */
# define ASN1_TFLG_SET_OF (0x1 << 1)
/* Field is a SEQUENCE OF */
# define ASN1_TFLG_SEQUENCE_OF (0x2 << 1)
/*
* Special case: this refers to a SET OF that will be sorted into DER order
* when encoded *and* the corresponding STACK will be modified to match the
* new order.
*/
# define ASN1_TFLG_SET_ORDER (0x3 << 1)
/* Mask for SET OF or SEQUENCE OF */
# define ASN1_TFLG_SK_MASK (0x3 << 1)
/*
* These flags mean the tag should be taken from the tag field. If EXPLICIT
* then the underlying type is used for the inner tag.
*/
/* IMPLICIT tagging */
# define ASN1_TFLG_IMPTAG (0x1 << 3)
/* EXPLICIT tagging, inner tag from underlying type */
# define ASN1_TFLG_EXPTAG (0x2 << 3)
# define ASN1_TFLG_TAG_MASK (0x3 << 3)
/* context specific IMPLICIT */
# define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT
/* context specific EXPLICIT */
# define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT
/*
* If tagging is in force these determine the type of tag to use. Otherwise
* the tag is determined by the underlying type. These values reflect the
* actual octet format.
*/
/* Universal tag */
# define ASN1_TFLG_UNIVERSAL (0x0<<6)
/* Application tag */
# define ASN1_TFLG_APPLICATION (0x1<<6)
/* Context specific tag */
# define ASN1_TFLG_CONTEXT (0x2<<6)
/* Private tag */
# define ASN1_TFLG_PRIVATE (0x3<<6)
# define ASN1_TFLG_TAG_CLASS (0x3<<6)
/*
* These are for ANY DEFINED BY type. In this case the 'item' field points to
* an ASN1_ADB structure which contains a table of values to decode the
* relevant type
*/
# define ASN1_TFLG_ADB_MASK (0x3<<8)
# define ASN1_TFLG_ADB_OID (0x1<<8)
# define ASN1_TFLG_ADB_INT (0x1<<9)
/*
* This flag means a parent structure is passed instead of the field: this is
* useful is a SEQUENCE is being combined with a CHOICE for example. Since
* this means the structure and item name will differ we need to use the
* ASN1_CHOICE_END_name() macro for example.
*/
# define ASN1_TFLG_COMBINE (0x1<<10)
/*
* This flag when present in a SEQUENCE OF, SET OF or EXPLICIT causes
* indefinite length constructed encoding to be used if required.
*/
# define ASN1_TFLG_NDEF (0x1<<11)
/* This is the actual ASN1 item itself */
struct ASN1_ITEM_st {
char itype; /* The item type, primitive, SEQUENCE, CHOICE
* or extern */
long utype; /* underlying type */
const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains
* the contents */
long tcount; /* Number of templates if SEQUENCE or CHOICE */
const void *funcs; /* functions that handle this type */
long size; /* Structure size (usually) */
# ifndef NO_ASN1_FIELD_NAMES
const char *sname; /* Structure name */
# endif
};
/*-
* These are values for the itype field and
* determine how the type is interpreted.
*
* For PRIMITIVE types the underlying type
* determines the behaviour if items is NULL.
*
* Otherwise templates must contain a single
* template and the type is treated in the
* same way as the type specified in the template.
*
* For SEQUENCE types the templates field points
* to the members, the size field is the
* structure size.
*
* For CHOICE types the templates field points
* to each possible member (typically a union)
* and the 'size' field is the offset of the
* selector.
*
* The 'funcs' field is used for application
* specific functions.
*
* For COMPAT types the funcs field gives a
* set of functions that handle this type, this
* supports the old d2i, i2d convention.
*
* The EXTERN type uses a new style d2i/i2d.
* The new style should be used where possible
* because it avoids things like the d2i IMPLICIT
* hack.
*
* MSTRING is a multiple string type, it is used
* for a CHOICE of character strings where the
* actual strings all occupy an ASN1_STRING
* structure. In this case the 'utype' field
* has a special meaning, it is used as a mask
* of acceptable types using the B_ASN1 constants.
*
* NDEF_SEQUENCE is the same as SEQUENCE except
* that it will use indefinite length constructed
* encoding if requested.
*
*/
# define ASN1_ITYPE_PRIMITIVE 0x0
# define ASN1_ITYPE_SEQUENCE 0x1
# define ASN1_ITYPE_CHOICE 0x2
# define ASN1_ITYPE_COMPAT 0x3
# define ASN1_ITYPE_EXTERN 0x4
# define ASN1_ITYPE_MSTRING 0x5
# define ASN1_ITYPE_NDEF_SEQUENCE 0x6
/*
* Cache for ASN1 tag and length, so we don't keep re-reading it for things
* like CHOICE
*/
struct ASN1_TLC_st {
char valid; /* Values below are valid */
int ret; /* return value */
long plen; /* length */
int ptag; /* class value */
int pclass; /* class value */
int hdrlen; /* header length */
};
/* Typedefs for ASN1 function pointers */
typedef ASN1_VALUE *ASN1_new_func(void);
typedef void ASN1_free_func(ASN1_VALUE *a);
typedef ASN1_VALUE *ASN1_d2i_func(ASN1_VALUE **a, const unsigned char **in,
long length);
typedef int ASN1_i2d_func(ASN1_VALUE *a, unsigned char **in);
typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
const ASN1_ITEM *it, int tag, int aclass, char opt,
ASN1_TLC *ctx);
typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass);
typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval,
int indent, const char *fname,
const ASN1_PCTX *pctx);
typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont,
int *putype, const ASN1_ITEM *it);
typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont,
int len, int utype, char *free_cont,
const ASN1_ITEM *it);
typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval,
const ASN1_ITEM *it, int indent,
const ASN1_PCTX *pctx);
typedef struct ASN1_COMPAT_FUNCS_st {
ASN1_new_func *asn1_new;
ASN1_free_func *asn1_free;
ASN1_d2i_func *asn1_d2i;
ASN1_i2d_func *asn1_i2d;
} ASN1_COMPAT_FUNCS;
typedef struct ASN1_EXTERN_FUNCS_st {
void *app_data;
ASN1_ex_new_func *asn1_ex_new;
ASN1_ex_free_func *asn1_ex_free;
ASN1_ex_free_func *asn1_ex_clear;
ASN1_ex_d2i *asn1_ex_d2i;
ASN1_ex_i2d *asn1_ex_i2d;
ASN1_ex_print_func *asn1_ex_print;
} ASN1_EXTERN_FUNCS;
typedef struct ASN1_PRIMITIVE_FUNCS_st {
void *app_data;
unsigned long flags;
ASN1_ex_new_func *prim_new;
ASN1_ex_free_func *prim_free;
ASN1_ex_free_func *prim_clear;
ASN1_primitive_c2i *prim_c2i;
ASN1_primitive_i2c *prim_i2c;
ASN1_primitive_print *prim_print;
} ASN1_PRIMITIVE_FUNCS;
/*
* This is the ASN1_AUX structure: it handles various miscellaneous
* requirements. For example the use of reference counts and an informational
* callback. The "informational callback" is called at various points during
* the ASN1 encoding and decoding. It can be used to provide minor
* customisation of the structures used. This is most useful where the
* supplied routines *almost* do the right thing but need some extra help at
* a few points. If the callback returns zero then it is assumed a fatal
* error has occurred and the main operation should be abandoned. If major
* changes in the default behaviour are required then an external type is
* more appropriate.
*/
typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it,
void *exarg);
typedef struct ASN1_AUX_st {
void *app_data;
int flags;
int ref_offset; /* Offset of reference value */
int ref_lock; /* Lock type to use */
ASN1_aux_cb *asn1_cb;
int enc_offset; /* Offset of ASN1_ENCODING structure */
} ASN1_AUX;
/* For print related callbacks exarg points to this structure */
typedef struct ASN1_PRINT_ARG_st {
BIO *out;
int indent;
const ASN1_PCTX *pctx;
} ASN1_PRINT_ARG;
/* For streaming related callbacks exarg points to this structure */
typedef struct ASN1_STREAM_ARG_st {
/* BIO to stream through */
BIO *out;
/* BIO with filters appended */
BIO *ndef_bio;
/* Streaming I/O boundary */
unsigned char **boundary;
} ASN1_STREAM_ARG;
/* Flags in ASN1_AUX */
/* Use a reference count */
# define ASN1_AFLG_REFCOUNT 1
/* Save the encoding of structure (useful for signatures) */
# define ASN1_AFLG_ENCODING 2
/* The Sequence length is invalid */
# define ASN1_AFLG_BROKEN 4
/* operation values for asn1_cb */
# define ASN1_OP_NEW_PRE 0
# define ASN1_OP_NEW_POST 1
# define ASN1_OP_FREE_PRE 2
# define ASN1_OP_FREE_POST 3
# define ASN1_OP_D2I_PRE 4
# define ASN1_OP_D2I_POST 5
# define ASN1_OP_I2D_PRE 6
# define ASN1_OP_I2D_POST 7
# define ASN1_OP_PRINT_PRE 8
# define ASN1_OP_PRINT_POST 9
# define ASN1_OP_STREAM_PRE 10
# define ASN1_OP_STREAM_POST 11
# define ASN1_OP_DETACHED_PRE 12
# define ASN1_OP_DETACHED_POST 13
/* Macro to implement a primitive type */
# define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
# define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
ASN1_ITEM_start(itname) \
ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \
ASN1_ITEM_end(itname)
/* Macro to implement a multi string type */
# define IMPLEMENT_ASN1_MSTRING(itname, mask) \
ASN1_ITEM_start(itname) \
ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \
ASN1_ITEM_end(itname)
/* Macro to implement an ASN1_ITEM in terms of old style funcs */
# define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE)
# define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \
static const ASN1_COMPAT_FUNCS sname##_ff = { \
(ASN1_new_func *)sname##_new, \
(ASN1_free_func *)sname##_free, \
(ASN1_d2i_func *)d2i_##sname, \
(ASN1_i2d_func *)i2d_##sname, \
}; \
ASN1_ITEM_start(sname) \
ASN1_ITYPE_COMPAT, \
tag, \
NULL, \
0, \
&sname##_ff, \
0, \
#sname \
ASN1_ITEM_end(sname)
# define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \
ASN1_ITEM_start(sname) \
ASN1_ITYPE_EXTERN, \
tag, \
NULL, \
0, \
&fptrs, \
0, \
#sname \
ASN1_ITEM_end(sname)
/* Macro to implement standard functions in terms of ASN1_ITEM structures */
# define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
# define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)
# define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname)
# define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \
IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname)
# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \
IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)
# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \
pre stname *fname##_new(void) \
{ \
return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
} \
pre void fname##_free(stname *a) \
{ \
ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
}
# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
stname *fname##_new(void) \
{ \
return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
} \
void fname##_free(stname *a) \
{ \
ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
}
# define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
{ \
return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
} \
int i2d_##fname(stname *a, unsigned char **out) \
{ \
return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
}
# define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
int i2d_##stname##_NDEF(stname *a, unsigned char **out) \
{ \
return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\
}
/*
* This includes evil casts to remove const: they will go away when full ASN1
* constification is done.
*/
# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
{ \
return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
} \
int i2d_##fname(const stname *a, unsigned char **out) \
{ \
return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
}
# define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \
stname * stname##_dup(stname *x) \
{ \
return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \
}
# define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \
IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname)
# define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \
int fname##_print_ctx(BIO *out, stname *x, int indent, \
const ASN1_PCTX *pctx) \
{ \
return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \
ASN1_ITEM_rptr(itname), pctx); \
}
# define IMPLEMENT_ASN1_FUNCTIONS_const(name) \
IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name)
# define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
/* external definitions for primitive types */
DECLARE_ASN1_ITEM(ASN1_BOOLEAN)
DECLARE_ASN1_ITEM(ASN1_TBOOLEAN)
DECLARE_ASN1_ITEM(ASN1_FBOOLEAN)
DECLARE_ASN1_ITEM(ASN1_SEQUENCE)
DECLARE_ASN1_ITEM(CBIGNUM)
DECLARE_ASN1_ITEM(BIGNUM)
DECLARE_ASN1_ITEM(LONG)
DECLARE_ASN1_ITEM(ZLONG)
DECLARE_STACK_OF(ASN1_VALUE)
/* Functions used internally by the ASN1 code */
int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
const ASN1_TEMPLATE *tt);
int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
const ASN1_ITEM *it, int tag, int aclass, char opt,
ASN1_TLC *ctx);
int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass);
int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out,
const ASN1_TEMPLATE *tt);
void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it);
int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it);
int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
const ASN1_ITEM *it);
ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
int nullerr);
int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
const ASN1_ITEM *it);
int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
const ASN1_ITEM *it);
#ifdef __cplusplus
}
#endif
#endif

553
cms/lib/cms.h Normal file
View file

@ -0,0 +1,553 @@
/* crypto/cms/cms.h */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#ifndef HEADER_CMS_H
# define HEADER_CMS_H
#include "libressl_cms.h"
#include "libressl_evp.h"
# include <openssl/x509.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct CMS_ContentInfo_st CMS_ContentInfo;
typedef struct CMS_SignerInfo_st CMS_SignerInfo;
typedef struct CMS_CertificateChoices CMS_CertificateChoices;
typedef struct CMS_RevocationInfoChoice_st CMS_RevocationInfoChoice;
typedef struct CMS_RecipientInfo_st CMS_RecipientInfo;
typedef struct CMS_ReceiptRequest_st CMS_ReceiptRequest;
typedef struct CMS_Receipt_st CMS_Receipt;
typedef struct CMS_RecipientEncryptedKey_st CMS_RecipientEncryptedKey;
typedef struct CMS_OtherKeyAttribute_st CMS_OtherKeyAttribute;
DECLARE_STACK_OF(CMS_SignerInfo)
DECLARE_STACK_OF(GENERAL_NAMES)
DECLARE_STACK_OF(CMS_RecipientEncryptedKey)
DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
# define CMS_SIGNERINFO_ISSUER_SERIAL 0
# define CMS_SIGNERINFO_KEYIDENTIFIER 1
# define CMS_RECIPINFO_NONE -1
# define CMS_RECIPINFO_TRANS 0
# define CMS_RECIPINFO_AGREE 1
# define CMS_RECIPINFO_KEK 2
# define CMS_RECIPINFO_PASS 3
# define CMS_RECIPINFO_OTHER 4
/* S/MIME related flags */
# define CMS_TEXT 0x1
# define CMS_NOCERTS 0x2
# define CMS_NO_CONTENT_VERIFY 0x4
# define CMS_NO_ATTR_VERIFY 0x8
# define CMS_NOSIGS \
(CMS_NO_CONTENT_VERIFY|CMS_NO_ATTR_VERIFY)
# define CMS_NOINTERN 0x10
# define CMS_NO_SIGNER_CERT_VERIFY 0x20
# define CMS_NOVERIFY 0x20
# define CMS_DETACHED 0x40
# define CMS_BINARY 0x80
# define CMS_NOATTR 0x100
# define CMS_NOSMIMECAP 0x200
# define CMS_NOOLDMIMETYPE 0x400
# define CMS_CRLFEOL 0x800
# define CMS_STREAM 0x1000
# define CMS_NOCRL 0x2000
# define CMS_PARTIAL 0x4000
# define CMS_REUSE_DIGEST 0x8000
# define CMS_USE_KEYID 0x10000
# define CMS_DEBUG_DECRYPT 0x20000
# define CMS_KEY_PARAM 0x40000
const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms);
BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont);
int CMS_dataFinal(CMS_ContentInfo *cms, BIO *bio);
ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms);
int CMS_is_detached(CMS_ContentInfo *cms);
int CMS_set_detached(CMS_ContentInfo *cms, int detached);
# ifdef HEADER_PEM_H
DECLARE_PEM_rw_const(CMS, CMS_ContentInfo)
# endif
int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms);
CMS_ContentInfo *d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms);
int i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms);
BIO *BIO_new_CMS(BIO *out, CMS_ContentInfo *cms);
int i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags);
int PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in,
int flags);
CMS_ContentInfo *SMIME_read_CMS(BIO *bio, BIO **bcont);
int SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags);
int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont,
unsigned int flags);
CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
STACK_OF(X509) *certs, BIO *data,
unsigned int flags);
CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
X509 *signcert, EVP_PKEY *pkey,
STACK_OF(X509) *certs, unsigned int flags);
int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags);
CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags);
int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
unsigned int flags);
CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
unsigned int flags);
int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
const unsigned char *key, size_t keylen,
BIO *dcont, BIO *out, unsigned int flags);
CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
const unsigned char *key,
size_t keylen, unsigned int flags);
int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
const unsigned char *key, size_t keylen);
int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
X509_STORE *store, BIO *dcont, BIO *out, unsigned int flags);
int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
STACK_OF(X509) *certs,
X509_STORE *store, unsigned int flags);
STACK_OF(X509) *CMS_get0_signers(CMS_ContentInfo *cms);
CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
const EVP_CIPHER *cipher, unsigned int flags);
int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pkey, X509 *cert,
BIO *dcont, BIO *out, unsigned int flags);
int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
unsigned char *key, size_t keylen,
unsigned char *id, size_t idlen);
int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
unsigned char *pass, ossl_ssize_t passlen);
STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri);
CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
X509 *recip, unsigned int flags);
int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey);
int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
EVP_PKEY **pk, X509 **recip,
X509_ALGOR **palg);
int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
ASN1_OCTET_STRING **keyid,
X509_NAME **issuer,
ASN1_INTEGER **sno);
CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
unsigned char *key, size_t keylen,
unsigned char *id, size_t idlen,
ASN1_GENERALIZEDTIME *date,
ASN1_OBJECT *otherTypeId,
ASN1_TYPE *otherType);
int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
X509_ALGOR **palg,
ASN1_OCTET_STRING **pid,
ASN1_GENERALIZEDTIME **pdate,
ASN1_OBJECT **potherid,
ASN1_TYPE **pothertype);
int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
unsigned char *key, size_t keylen);
int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
const unsigned char *id, size_t idlen);
int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
unsigned char *pass,
ossl_ssize_t passlen);
CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
int iter, int wrap_nid,
int pbe_nid,
unsigned char *pass,
ossl_ssize_t passlen,
const EVP_CIPHER *kekciph);
int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
int CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
unsigned int flags);
CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags);
int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid);
const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms);
CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms);
int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert);
int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert);
STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms);
CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms);
int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl);
int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl);
STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms);
int CMS_SignedData_init(CMS_ContentInfo *cms);
CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
X509 *signer, EVP_PKEY *pk, const EVP_MD *md,
unsigned int flags);
EVP_PKEY_CTX *CMS_SignerInfo_get0_pkey_ctx(CMS_SignerInfo *si);
EVP_MD_CTX *CMS_SignerInfo_get0_md_ctx(CMS_SignerInfo *si);
STACK_OF(CMS_SignerInfo) *CMS_get0_SignerInfos(CMS_ContentInfo *cms);
void CMS_SignerInfo_set1_signer_cert(CMS_SignerInfo *si, X509 *signer);
int CMS_SignerInfo_get0_signer_id(CMS_SignerInfo *si,
ASN1_OCTET_STRING **keyid,
X509_NAME **issuer, ASN1_INTEGER **sno);
int CMS_SignerInfo_cert_cmp(CMS_SignerInfo *si, X509 *cert);
int CMS_set1_signers_certs(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
unsigned int flags);
void CMS_SignerInfo_get0_algs(CMS_SignerInfo *si, EVP_PKEY **pk,
X509 **signer, X509_ALGOR **pdig,
X509_ALGOR **psig);
ASN1_OCTET_STRING *CMS_SignerInfo_get0_signature(CMS_SignerInfo *si);
int CMS_SignerInfo_sign(CMS_SignerInfo *si);
int CMS_SignerInfo_verify(CMS_SignerInfo *si);
int CMS_SignerInfo_verify_content(CMS_SignerInfo *si, BIO *chain);
int CMS_add_smimecap(CMS_SignerInfo *si, STACK_OF(X509_ALGOR) *algs);
int CMS_add_simple_smimecap(STACK_OF(X509_ALGOR) **algs,
int algnid, int keysize);
int CMS_add_standard_smimecap(STACK_OF(X509_ALGOR) **smcap);
int CMS_signed_get_attr_count(const CMS_SignerInfo *si);
int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
int lastpos);
int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
int lastpos);
X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc);
X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc);
int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si,
const ASN1_OBJECT *obj, int type,
const void *bytes, int len);
int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
int nid, int type,
const void *bytes, int len);
int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
const char *attrname, int type,
const void *bytes, int len);
void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
int lastpos, int type);
int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si);
int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
int lastpos);
int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
int lastpos);
X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc);
X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc);
int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr);
int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si,
const ASN1_OBJECT *obj, int type,
const void *bytes, int len);
int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si,
int nid, int type,
const void *bytes, int len);
int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
const char *attrname, int type,
const void *bytes, int len);
void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
int lastpos, int type);
# ifdef HEADER_X509V3_H
int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr);
CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
int allorfirst,
STACK_OF(GENERAL_NAMES)
*receiptList, STACK_OF(GENERAL_NAMES)
*receiptsTo);
int CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr);
void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
ASN1_STRING **pcid,
int *pallorfirst,
STACK_OF(GENERAL_NAMES) **plist,
STACK_OF(GENERAL_NAMES) **prto);
# endif
int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
X509_ALGOR **palg,
ASN1_OCTET_STRING **pukm);
STACK_OF(CMS_RecipientEncryptedKey)
*CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri);
int CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri,
X509_ALGOR **pubalg,
ASN1_BIT_STRING **pubkey,
ASN1_OCTET_STRING **keyid,
X509_NAME **issuer,
ASN1_INTEGER **sno);
int CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert);
int CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
ASN1_OCTET_STRING **keyid,
ASN1_GENERALIZEDTIME **tm,
CMS_OtherKeyAttribute **other,
X509_NAME **issuer, ASN1_INTEGER **sno);
int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
X509 *cert);
int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk);
EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri);
int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms,
CMS_RecipientInfo *ri,
CMS_RecipientEncryptedKey *rek);
int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg,
ASN1_OCTET_STRING *ukm, int keylen);
/* BEGIN ERROR CODES */
/*
* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
*/
void ERR_load_CMS_strings(void);
/* Error codes for the CMS functions. */
/* Function codes. */
# define CMS_F_CHECK_CONTENT 99
# define CMS_F_CMS_ADD0_CERT 164
# define CMS_F_CMS_ADD0_RECIPIENT_KEY 100
# define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD 165
# define CMS_F_CMS_ADD1_RECEIPTREQUEST 158
# define CMS_F_CMS_ADD1_RECIPIENT_CERT 101
# define CMS_F_CMS_ADD1_SIGNER 102
# define CMS_F_CMS_ADD1_SIGNINGTIME 103
# define CMS_F_CMS_COMPRESS 104
# define CMS_F_CMS_COMPRESSEDDATA_CREATE 105
# define CMS_F_CMS_COMPRESSEDDATA_INIT_BIO 106
# define CMS_F_CMS_COPY_CONTENT 107
# define CMS_F_CMS_COPY_MESSAGEDIGEST 108
# define CMS_F_CMS_DATA 109
# define CMS_F_CMS_DATAFINAL 110
# define CMS_F_CMS_DATAINIT 111
# define CMS_F_CMS_DECRYPT 112
# define CMS_F_CMS_DECRYPT_SET1_KEY 113
# define CMS_F_CMS_DECRYPT_SET1_PASSWORD 166
# define CMS_F_CMS_DECRYPT_SET1_PKEY 114
# define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 115
# define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 116
# define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 117
# define CMS_F_CMS_DIGEST_VERIFY 118
# define CMS_F_CMS_ENCODE_RECEIPT 161
# define CMS_F_CMS_ENCRYPT 119
# define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 120
# define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 121
# define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT 122
# define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 123
# define CMS_F_CMS_ENVELOPEDDATA_CREATE 124
# define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 125
# define CMS_F_CMS_ENVELOPED_DATA_INIT 126
# define CMS_F_CMS_ENV_ASN1_CTRL 171
# define CMS_F_CMS_FINAL 127
# define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 128
# define CMS_F_CMS_GET0_CONTENT 129
# define CMS_F_CMS_GET0_ECONTENT_TYPE 130
# define CMS_F_CMS_GET0_ENVELOPED 131
# define CMS_F_CMS_GET0_REVOCATION_CHOICES 132
# define CMS_F_CMS_GET0_SIGNED 133
# define CMS_F_CMS_MSGSIGDIGEST_ADD1 162
# define CMS_F_CMS_RECEIPTREQUEST_CREATE0 159
# define CMS_F_CMS_RECEIPT_VERIFY 160
# define CMS_F_CMS_RECIPIENTINFO_DECRYPT 134
# define CMS_F_CMS_RECIPIENTINFO_ENCRYPT 169
# define CMS_F_CMS_RECIPIENTINFO_KARI_ENCRYPT 178
# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ALG 175
# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_ORIG_ID 173
# define CMS_F_CMS_RECIPIENTINFO_KARI_GET0_REKS 172
# define CMS_F_CMS_RECIPIENTINFO_KARI_ORIG_ID_CMP 174
# define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 135
# define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 136
# define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 137
# define CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP 138
# define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 139
# define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 140
# define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 141
# define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 142
# define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 143
# define CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT 167
# define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 144
# define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD 168
# define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 145
# define CMS_F_CMS_SD_ASN1_CTRL 170
# define CMS_F_CMS_SET1_IAS 176
# define CMS_F_CMS_SET1_KEYID 177
# define CMS_F_CMS_SET1_SIGNERIDENTIFIER 146
# define CMS_F_CMS_SET_DETACHED 147
# define CMS_F_CMS_SIGN 148
# define CMS_F_CMS_SIGNED_DATA_INIT 149
# define CMS_F_CMS_SIGNERINFO_CONTENT_SIGN 150
# define CMS_F_CMS_SIGNERINFO_SIGN 151
# define CMS_F_CMS_SIGNERINFO_VERIFY 152
# define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 153
# define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT 154
# define CMS_F_CMS_SIGN_RECEIPT 163
# define CMS_F_CMS_STREAM 155
# define CMS_F_CMS_UNCOMPRESS 156
# define CMS_F_CMS_VERIFY 157
/* Reason codes. */
# define CMS_R_ADD_SIGNER_ERROR 99
# define CMS_R_CERTIFICATE_ALREADY_PRESENT 175
# define CMS_R_CERTIFICATE_HAS_NO_KEYID 160
# define CMS_R_CERTIFICATE_VERIFY_ERROR 100
# define CMS_R_CIPHER_INITIALISATION_ERROR 101
# define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR 102
# define CMS_R_CMS_DATAFINAL_ERROR 103
# define CMS_R_CMS_LIB 104
# define CMS_R_CONTENTIDENTIFIER_MISMATCH 170
# define CMS_R_CONTENT_NOT_FOUND 105
# define CMS_R_CONTENT_TYPE_MISMATCH 171
# define CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA 106
# define CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA 107
# define CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA 108
# define CMS_R_CONTENT_VERIFY_ERROR 109
# define CMS_R_CTRL_ERROR 110
# define CMS_R_CTRL_FAILURE 111
# define CMS_R_DECRYPT_ERROR 112
# define CMS_R_DIGEST_ERROR 161
# define CMS_R_ERROR_GETTING_PUBLIC_KEY 113
# define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114
# define CMS_R_ERROR_SETTING_KEY 115
# define CMS_R_ERROR_SETTING_RECIPIENTINFO 116
# define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117
# define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176
# define CMS_R_INVALID_KEY_LENGTH 118
# define CMS_R_MD_BIO_INIT_ERROR 119
# define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 120
# define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 121
# define CMS_R_MSGSIGDIGEST_ERROR 172
# define CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE 162
# define CMS_R_MSGSIGDIGEST_WRONG_LENGTH 163
# define CMS_R_NEED_ONE_SIGNER 164
# define CMS_R_NOT_A_SIGNED_RECEIPT 165
# define CMS_R_NOT_ENCRYPTED_DATA 122
# define CMS_R_NOT_KEK 123
# define CMS_R_NOT_KEY_AGREEMENT 181
# define CMS_R_NOT_KEY_TRANSPORT 124
# define CMS_R_NOT_PWRI 177
# define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 125
# define CMS_R_NO_CIPHER 126
# define CMS_R_NO_CONTENT 127
# define CMS_R_NO_CONTENT_TYPE 173
# define CMS_R_NO_DEFAULT_DIGEST 128
# define CMS_R_NO_DIGEST_SET 129
# define CMS_R_NO_KEY 130
# define CMS_R_NO_KEY_OR_CERT 174
# define CMS_R_NO_MATCHING_DIGEST 131
# define CMS_R_NO_MATCHING_RECIPIENT 132
# define CMS_R_NO_MATCHING_SIGNATURE 166
# define CMS_R_NO_MSGSIGDIGEST 167
# define CMS_R_NO_PASSWORD 178
# define CMS_R_NO_PRIVATE_KEY 133
# define CMS_R_NO_PUBLIC_KEY 134
# define CMS_R_NO_RECEIPT_REQUEST 168
# define CMS_R_NO_SIGNERS 135
# define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 136
# define CMS_R_RECEIPT_DECODE_ERROR 169
# define CMS_R_RECIPIENT_ERROR 137
# define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 138
# define CMS_R_SIGNFINAL_ERROR 139
# define CMS_R_SMIME_TEXT_ERROR 140
# define CMS_R_STORE_INIT_ERROR 141
# define CMS_R_TYPE_NOT_COMPRESSED_DATA 142
# define CMS_R_TYPE_NOT_DATA 143
# define CMS_R_TYPE_NOT_DIGESTED_DATA 144
# define CMS_R_TYPE_NOT_ENCRYPTED_DATA 145
# define CMS_R_TYPE_NOT_ENVELOPED_DATA 146
# define CMS_R_UNABLE_TO_FINALIZE_CONTEXT 147
# define CMS_R_UNKNOWN_CIPHER 148
# define CMS_R_UNKNOWN_DIGEST_ALGORIHM 149
# define CMS_R_UNKNOWN_ID 150
# define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 151
# define CMS_R_UNSUPPORTED_CONTENT_TYPE 152
# define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153
# define CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM 179
# define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154
# define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 155
# define CMS_R_UNSUPPORTED_TYPE 156
# define CMS_R_UNWRAP_ERROR 157
# define CMS_R_UNWRAP_FAILURE 180
# define CMS_R_VERIFICATION_FAILURE 158
# define CMS_R_WRAP_ERROR 159
#ifdef __cplusplus
}
#endif
#endif

459
cms/lib/cms_asn1.c Normal file
View file

@ -0,0 +1,459 @@
/* crypto/cms/cms_asn1.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include "cms.h"
#include "cms_lcl.h"
ASN1_SEQUENCE(CMS_IssuerAndSerialNumber) = {
ASN1_SIMPLE(CMS_IssuerAndSerialNumber, issuer, X509_NAME),
ASN1_SIMPLE(CMS_IssuerAndSerialNumber, serialNumber, ASN1_INTEGER)
} ASN1_SEQUENCE_END(CMS_IssuerAndSerialNumber)
ASN1_SEQUENCE(CMS_OtherCertificateFormat) = {
ASN1_SIMPLE(CMS_OtherCertificateFormat, otherCertFormat, ASN1_OBJECT),
ASN1_OPT(CMS_OtherCertificateFormat, otherCert, ASN1_ANY)
} ASN1_SEQUENCE_END(CMS_OtherCertificateFormat)
ASN1_CHOICE(CMS_CertificateChoices) = {
ASN1_SIMPLE(CMS_CertificateChoices, d.certificate, X509),
ASN1_IMP(CMS_CertificateChoices, d.extendedCertificate, ASN1_SEQUENCE, 0),
ASN1_IMP(CMS_CertificateChoices, d.v1AttrCert, ASN1_SEQUENCE, 1),
ASN1_IMP(CMS_CertificateChoices, d.v2AttrCert, ASN1_SEQUENCE, 2),
ASN1_IMP(CMS_CertificateChoices, d.other, CMS_OtherCertificateFormat, 3)
} ASN1_CHOICE_END(CMS_CertificateChoices)
ASN1_CHOICE(CMS_SignerIdentifier) = {
ASN1_SIMPLE(CMS_SignerIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
ASN1_IMP(CMS_SignerIdentifier, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0)
} ASN1_CHOICE_END(CMS_SignerIdentifier)
ASN1_NDEF_SEQUENCE(CMS_EncapsulatedContentInfo) = {
ASN1_SIMPLE(CMS_EncapsulatedContentInfo, eContentType, ASN1_OBJECT),
ASN1_NDEF_EXP_OPT(CMS_EncapsulatedContentInfo, eContent, ASN1_OCTET_STRING_NDEF, 0)
} ASN1_NDEF_SEQUENCE_END(CMS_EncapsulatedContentInfo)
/* Minor tweak to operation: free up signer key, cert */
static int cms_si_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
if (operation == ASN1_OP_FREE_POST) {
CMS_SignerInfo *si = (CMS_SignerInfo *)*pval;
if (si->pkey)
EVP_PKEY_free(si->pkey);
if (si->signer)
X509_free(si->signer);
if (si->pctx)
EVP_MD_CTX_cleanup(&si->mctx);
}
return 1;
}
ASN1_SEQUENCE_cb(CMS_SignerInfo, cms_si_cb) = {
ASN1_SIMPLE(CMS_SignerInfo, version, LONG),
ASN1_SIMPLE(CMS_SignerInfo, sid, CMS_SignerIdentifier),
ASN1_SIMPLE(CMS_SignerInfo, digestAlgorithm, X509_ALGOR),
ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, signedAttrs, X509_ATTRIBUTE, 0),
ASN1_SIMPLE(CMS_SignerInfo, signatureAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_SignerInfo, signature, ASN1_OCTET_STRING),
ASN1_IMP_SET_OF_OPT(CMS_SignerInfo, unsignedAttrs, X509_ATTRIBUTE, 1)
} ASN1_SEQUENCE_END_cb(CMS_SignerInfo, CMS_SignerInfo)
ASN1_SEQUENCE(CMS_OtherRevocationInfoFormat) = {
ASN1_SIMPLE(CMS_OtherRevocationInfoFormat, otherRevInfoFormat, ASN1_OBJECT),
ASN1_OPT(CMS_OtherRevocationInfoFormat, otherRevInfo, ASN1_ANY)
} ASN1_SEQUENCE_END(CMS_OtherRevocationInfoFormat)
ASN1_CHOICE(CMS_RevocationInfoChoice) = {
ASN1_SIMPLE(CMS_RevocationInfoChoice, d.crl, X509_CRL),
ASN1_IMP(CMS_RevocationInfoChoice, d.other, CMS_OtherRevocationInfoFormat, 1)
} ASN1_CHOICE_END(CMS_RevocationInfoChoice)
ASN1_NDEF_SEQUENCE(CMS_SignedData) = {
ASN1_SIMPLE(CMS_SignedData, version, LONG),
ASN1_SET_OF(CMS_SignedData, digestAlgorithms, X509_ALGOR),
ASN1_SIMPLE(CMS_SignedData, encapContentInfo, CMS_EncapsulatedContentInfo),
ASN1_IMP_SET_OF_OPT(CMS_SignedData, certificates, CMS_CertificateChoices, 0),
ASN1_IMP_SET_OF_OPT(CMS_SignedData, crls, CMS_RevocationInfoChoice, 1),
ASN1_SET_OF(CMS_SignedData, signerInfos, CMS_SignerInfo)
} ASN1_NDEF_SEQUENCE_END(CMS_SignedData)
ASN1_SEQUENCE(CMS_OriginatorInfo) = {
ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, certificates, CMS_CertificateChoices, 0),
ASN1_IMP_SET_OF_OPT(CMS_OriginatorInfo, crls, CMS_RevocationInfoChoice, 1)
} ASN1_SEQUENCE_END(CMS_OriginatorInfo)
ASN1_NDEF_SEQUENCE(CMS_EncryptedContentInfo) = {
ASN1_SIMPLE(CMS_EncryptedContentInfo, contentType, ASN1_OBJECT),
ASN1_SIMPLE(CMS_EncryptedContentInfo, contentEncryptionAlgorithm, X509_ALGOR),
ASN1_IMP_OPT(CMS_EncryptedContentInfo, encryptedContent, ASN1_OCTET_STRING_NDEF, 0)
} ASN1_NDEF_SEQUENCE_END(CMS_EncryptedContentInfo)
ASN1_SEQUENCE(CMS_KeyTransRecipientInfo) = {
ASN1_SIMPLE(CMS_KeyTransRecipientInfo, version, LONG),
ASN1_SIMPLE(CMS_KeyTransRecipientInfo, rid, CMS_SignerIdentifier),
ASN1_SIMPLE(CMS_KeyTransRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_KeyTransRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CMS_KeyTransRecipientInfo)
ASN1_SEQUENCE(CMS_OtherKeyAttribute) = {
ASN1_SIMPLE(CMS_OtherKeyAttribute, keyAttrId, ASN1_OBJECT),
ASN1_OPT(CMS_OtherKeyAttribute, keyAttr, ASN1_ANY)
} ASN1_SEQUENCE_END(CMS_OtherKeyAttribute)
ASN1_SEQUENCE(CMS_RecipientKeyIdentifier) = {
ASN1_SIMPLE(CMS_RecipientKeyIdentifier, subjectKeyIdentifier, ASN1_OCTET_STRING),
ASN1_OPT(CMS_RecipientKeyIdentifier, date, ASN1_GENERALIZEDTIME),
ASN1_OPT(CMS_RecipientKeyIdentifier, other, CMS_OtherKeyAttribute)
} ASN1_SEQUENCE_END(CMS_RecipientKeyIdentifier)
ASN1_CHOICE(CMS_KeyAgreeRecipientIdentifier) = {
ASN1_SIMPLE(CMS_KeyAgreeRecipientIdentifier, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
ASN1_IMP(CMS_KeyAgreeRecipientIdentifier, d.rKeyId, CMS_RecipientKeyIdentifier, 0)
} ASN1_CHOICE_END(CMS_KeyAgreeRecipientIdentifier)
static int cms_rek_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
CMS_RecipientEncryptedKey *rek = (CMS_RecipientEncryptedKey *)*pval;
if (operation == ASN1_OP_FREE_POST) {
if (rek->pkey)
EVP_PKEY_free(rek->pkey);
}
return 1;
}
ASN1_SEQUENCE_cb(CMS_RecipientEncryptedKey, cms_rek_cb) = {
ASN1_SIMPLE(CMS_RecipientEncryptedKey, rid, CMS_KeyAgreeRecipientIdentifier),
ASN1_SIMPLE(CMS_RecipientEncryptedKey, encryptedKey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END_cb(CMS_RecipientEncryptedKey, CMS_RecipientEncryptedKey)
ASN1_SEQUENCE(CMS_OriginatorPublicKey) = {
ASN1_SIMPLE(CMS_OriginatorPublicKey, algorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_OriginatorPublicKey, publicKey, ASN1_BIT_STRING)
} ASN1_SEQUENCE_END(CMS_OriginatorPublicKey)
ASN1_CHOICE(CMS_OriginatorIdentifierOrKey) = {
ASN1_SIMPLE(CMS_OriginatorIdentifierOrKey, d.issuerAndSerialNumber, CMS_IssuerAndSerialNumber),
ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.subjectKeyIdentifier, ASN1_OCTET_STRING, 0),
ASN1_IMP(CMS_OriginatorIdentifierOrKey, d.originatorKey, CMS_OriginatorPublicKey, 1)
} ASN1_CHOICE_END(CMS_OriginatorIdentifierOrKey)
static int cms_kari_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
CMS_KeyAgreeRecipientInfo *kari = (CMS_KeyAgreeRecipientInfo *)*pval;
if (operation == ASN1_OP_NEW_POST) {
EVP_CIPHER_CTX_init(&kari->ctx);
EVP_CIPHER_CTX_set_flags(&kari->ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
kari->pctx = NULL;
} else if (operation == ASN1_OP_FREE_POST) {
if (kari->pctx)
EVP_PKEY_CTX_free(kari->pctx);
EVP_CIPHER_CTX_cleanup(&kari->ctx);
}
return 1;
}
ASN1_SEQUENCE_cb(CMS_KeyAgreeRecipientInfo, cms_kari_cb) = {
ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, version, LONG),
ASN1_EXP(CMS_KeyAgreeRecipientInfo, originator, CMS_OriginatorIdentifierOrKey, 0),
ASN1_EXP_OPT(CMS_KeyAgreeRecipientInfo, ukm, ASN1_OCTET_STRING, 1),
ASN1_SIMPLE(CMS_KeyAgreeRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
ASN1_SEQUENCE_OF(CMS_KeyAgreeRecipientInfo, recipientEncryptedKeys, CMS_RecipientEncryptedKey)
} ASN1_SEQUENCE_END_cb(CMS_KeyAgreeRecipientInfo, CMS_KeyAgreeRecipientInfo)
ASN1_SEQUENCE(CMS_KEKIdentifier) = {
ASN1_SIMPLE(CMS_KEKIdentifier, keyIdentifier, ASN1_OCTET_STRING),
ASN1_OPT(CMS_KEKIdentifier, date, ASN1_GENERALIZEDTIME),
ASN1_OPT(CMS_KEKIdentifier, other, CMS_OtherKeyAttribute)
} ASN1_SEQUENCE_END(CMS_KEKIdentifier)
ASN1_SEQUENCE(CMS_KEKRecipientInfo) = {
ASN1_SIMPLE(CMS_KEKRecipientInfo, version, LONG),
ASN1_SIMPLE(CMS_KEKRecipientInfo, kekid, CMS_KEKIdentifier),
ASN1_SIMPLE(CMS_KEKRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_KEKRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CMS_KEKRecipientInfo)
ASN1_SEQUENCE(CMS_PasswordRecipientInfo) = {
ASN1_SIMPLE(CMS_PasswordRecipientInfo, version, LONG),
ASN1_IMP_OPT(CMS_PasswordRecipientInfo, keyDerivationAlgorithm, X509_ALGOR, 0),
ASN1_SIMPLE(CMS_PasswordRecipientInfo, keyEncryptionAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_PasswordRecipientInfo, encryptedKey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CMS_PasswordRecipientInfo)
ASN1_SEQUENCE(CMS_OtherRecipientInfo) = {
ASN1_SIMPLE(CMS_OtherRecipientInfo, oriType, ASN1_OBJECT),
ASN1_OPT(CMS_OtherRecipientInfo, oriValue, ASN1_ANY)
} ASN1_SEQUENCE_END(CMS_OtherRecipientInfo)
/* Free up RecipientInfo additional data */
static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
if (operation == ASN1_OP_FREE_PRE) {
CMS_RecipientInfo *ri = (CMS_RecipientInfo *)*pval;
if (ri->type == CMS_RECIPINFO_TRANS) {
CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
if (ktri->pkey)
EVP_PKEY_free(ktri->pkey);
if (ktri->recip)
X509_free(ktri->recip);
if (ktri->pctx)
EVP_PKEY_CTX_free(ktri->pctx);
} else if (ri->type == CMS_RECIPINFO_KEK) {
CMS_KEKRecipientInfo *kekri = ri->d.kekri;
if (kekri->key) {
OPENSSL_cleanse(kekri->key, kekri->keylen);
OPENSSL_free(kekri->key);
}
} else if (ri->type == CMS_RECIPINFO_PASS) {
CMS_PasswordRecipientInfo *pwri = ri->d.pwri;
if (pwri->pass) {
OPENSSL_cleanse(pwri->pass, pwri->passlen);
OPENSSL_free(pwri->pass);
}
}
}
return 1;
}
ASN1_CHOICE_cb(CMS_RecipientInfo, cms_ri_cb) = {
ASN1_SIMPLE(CMS_RecipientInfo, d.ktri, CMS_KeyTransRecipientInfo),
ASN1_IMP(CMS_RecipientInfo, d.kari, CMS_KeyAgreeRecipientInfo, 1),
ASN1_IMP(CMS_RecipientInfo, d.kekri, CMS_KEKRecipientInfo, 2),
ASN1_IMP(CMS_RecipientInfo, d.pwri, CMS_PasswordRecipientInfo, 3),
ASN1_IMP(CMS_RecipientInfo, d.ori, CMS_OtherRecipientInfo, 4)
} ASN1_CHOICE_END_cb(CMS_RecipientInfo, CMS_RecipientInfo, type)
ASN1_NDEF_SEQUENCE(CMS_EnvelopedData) = {
ASN1_SIMPLE(CMS_EnvelopedData, version, LONG),
ASN1_IMP_OPT(CMS_EnvelopedData, originatorInfo, CMS_OriginatorInfo, 0),
ASN1_SET_OF(CMS_EnvelopedData, recipientInfos, CMS_RecipientInfo),
ASN1_SIMPLE(CMS_EnvelopedData, encryptedContentInfo, CMS_EncryptedContentInfo),
ASN1_IMP_SET_OF_OPT(CMS_EnvelopedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
} ASN1_NDEF_SEQUENCE_END(CMS_EnvelopedData)
ASN1_NDEF_SEQUENCE(CMS_DigestedData) = {
ASN1_SIMPLE(CMS_DigestedData, version, LONG),
ASN1_SIMPLE(CMS_DigestedData, digestAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_DigestedData, encapContentInfo, CMS_EncapsulatedContentInfo),
ASN1_SIMPLE(CMS_DigestedData, digest, ASN1_OCTET_STRING)
} ASN1_NDEF_SEQUENCE_END(CMS_DigestedData)
ASN1_NDEF_SEQUENCE(CMS_EncryptedData) = {
ASN1_SIMPLE(CMS_EncryptedData, version, LONG),
ASN1_SIMPLE(CMS_EncryptedData, encryptedContentInfo, CMS_EncryptedContentInfo),
ASN1_IMP_SET_OF_OPT(CMS_EncryptedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
} ASN1_NDEF_SEQUENCE_END(CMS_EncryptedData)
ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = {
ASN1_SIMPLE(CMS_AuthenticatedData, version, LONG),
ASN1_IMP_OPT(CMS_AuthenticatedData, originatorInfo, CMS_OriginatorInfo, 0),
ASN1_SET_OF(CMS_AuthenticatedData, recipientInfos, CMS_RecipientInfo),
ASN1_SIMPLE(CMS_AuthenticatedData, macAlgorithm, X509_ALGOR),
ASN1_IMP(CMS_AuthenticatedData, digestAlgorithm, X509_ALGOR, 1),
ASN1_SIMPLE(CMS_AuthenticatedData, encapContentInfo, CMS_EncapsulatedContentInfo),
ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, authAttrs, X509_ALGOR, 2),
ASN1_SIMPLE(CMS_AuthenticatedData, mac, ASN1_OCTET_STRING),
ASN1_IMP_SET_OF_OPT(CMS_AuthenticatedData, unauthAttrs, X509_ALGOR, 3)
} ASN1_NDEF_SEQUENCE_END(CMS_AuthenticatedData)
ASN1_NDEF_SEQUENCE(CMS_CompressedData) = {
ASN1_SIMPLE(CMS_CompressedData, version, LONG),
ASN1_SIMPLE(CMS_CompressedData, compressionAlgorithm, X509_ALGOR),
ASN1_SIMPLE(CMS_CompressedData, encapContentInfo, CMS_EncapsulatedContentInfo),
} ASN1_NDEF_SEQUENCE_END(CMS_CompressedData)
/* This is the ANY DEFINED BY table for the top level ContentInfo structure */
ASN1_ADB_TEMPLATE(cms_default) = ASN1_EXP(CMS_ContentInfo, d.other, ASN1_ANY, 0);
ASN1_ADB(CMS_ContentInfo) = {
ADB_ENTRY(NID_pkcs7_data, ASN1_NDEF_EXP(CMS_ContentInfo, d.data, ASN1_OCTET_STRING_NDEF, 0)),
ADB_ENTRY(NID_pkcs7_signed, ASN1_NDEF_EXP(CMS_ContentInfo, d.signedData, CMS_SignedData, 0)),
ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP(CMS_ContentInfo, d.envelopedData, CMS_EnvelopedData, 0)),
ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP(CMS_ContentInfo, d.digestedData, CMS_DigestedData, 0)),
ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP(CMS_ContentInfo, d.encryptedData, CMS_EncryptedData, 0)),
ADB_ENTRY(NID_id_smime_ct_authData, ASN1_NDEF_EXP(CMS_ContentInfo, d.authenticatedData, CMS_AuthenticatedData, 0)),
ADB_ENTRY(NID_id_smime_ct_compressedData, ASN1_NDEF_EXP(CMS_ContentInfo, d.compressedData, CMS_CompressedData, 0)),
} ASN1_ADB_END(CMS_ContentInfo, 0, contentType, 0, &cms_default_tt, NULL);
/* CMS streaming support */
static int cms_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
ASN1_STREAM_ARG *sarg = exarg;
CMS_ContentInfo *cms = NULL;
if (pval)
cms = (CMS_ContentInfo *)*pval;
else
return 1;
switch (operation) {
case ASN1_OP_STREAM_PRE:
if (CMS_stream(&sarg->boundary, cms) <= 0)
return 0;
case ASN1_OP_DETACHED_PRE:
sarg->ndef_bio = CMS_dataInit(cms, sarg->out);
if (!sarg->ndef_bio)
return 0;
break;
case ASN1_OP_STREAM_POST:
case ASN1_OP_DETACHED_POST:
if (CMS_dataFinal(cms, sarg->ndef_bio) <= 0)
return 0;
break;
}
return 1;
}
ASN1_NDEF_SEQUENCE_cb(CMS_ContentInfo, cms_cb) = {
ASN1_SIMPLE(CMS_ContentInfo, contentType, ASN1_OBJECT),
ASN1_ADB_OBJECT(CMS_ContentInfo)
} ASN1_NDEF_SEQUENCE_END_cb(CMS_ContentInfo, CMS_ContentInfo)
/* Specials for signed attributes */
/*
* When signing attributes we want to reorder them to match the sorted
* encoding.
*/
ASN1_ITEM_TEMPLATE(CMS_Attributes_Sign) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_ORDER, 0, CMS_ATTRIBUTES, X509_ATTRIBUTE)
ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Sign)
/*
* When verifying attributes we need to use the received order. So we use
* SEQUENCE OF and tag it to SET OF
*/
ASN1_ITEM_TEMPLATE(CMS_Attributes_Verify) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_UNIVERSAL,
V_ASN1_SET, CMS_ATTRIBUTES, X509_ATTRIBUTE)
ASN1_ITEM_TEMPLATE_END(CMS_Attributes_Verify)
ASN1_CHOICE(CMS_ReceiptsFrom) = {
ASN1_IMP(CMS_ReceiptsFrom, d.allOrFirstTier, LONG, 0),
ASN1_IMP_SEQUENCE_OF(CMS_ReceiptsFrom, d.receiptList, GENERAL_NAMES, 1)
} ASN1_CHOICE_END(CMS_ReceiptsFrom)
ASN1_SEQUENCE(CMS_ReceiptRequest) = {
ASN1_SIMPLE(CMS_ReceiptRequest, signedContentIdentifier, ASN1_OCTET_STRING),
ASN1_SIMPLE(CMS_ReceiptRequest, receiptsFrom, CMS_ReceiptsFrom),
ASN1_SEQUENCE_OF(CMS_ReceiptRequest, receiptsTo, GENERAL_NAMES)
} ASN1_SEQUENCE_END(CMS_ReceiptRequest)
ASN1_SEQUENCE(CMS_Receipt) = {
ASN1_SIMPLE(CMS_Receipt, version, LONG),
ASN1_SIMPLE(CMS_Receipt, contentType, ASN1_OBJECT),
ASN1_SIMPLE(CMS_Receipt, signedContentIdentifier, ASN1_OCTET_STRING),
ASN1_SIMPLE(CMS_Receipt, originatorSignatureValue, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CMS_Receipt)
/*
* Utilities to encode the CMS_SharedInfo structure used during key
* derivation.
*/
typedef struct {
X509_ALGOR *keyInfo;
ASN1_OCTET_STRING *entityUInfo;
ASN1_OCTET_STRING *suppPubInfo;
} CMS_SharedInfo;
ASN1_SEQUENCE(CMS_SharedInfo) = {
ASN1_SIMPLE(CMS_SharedInfo, keyInfo, X509_ALGOR),
ASN1_EXP_OPT(CMS_SharedInfo, entityUInfo, ASN1_OCTET_STRING, 0),
ASN1_EXP_OPT(CMS_SharedInfo, suppPubInfo, ASN1_OCTET_STRING, 2),
} ASN1_SEQUENCE_END(CMS_SharedInfo)
int CMS_SharedInfo_encode(unsigned char **pder, X509_ALGOR *kekalg,
ASN1_OCTET_STRING *ukm, int keylen)
{
union {
CMS_SharedInfo *pecsi;
ASN1_VALUE *a;
} intsi = {
NULL
};
ASN1_OCTET_STRING oklen;
unsigned char kl[4];
CMS_SharedInfo ecsi;
keylen <<= 3;
kl[0] = (keylen >> 24) & 0xff;
kl[1] = (keylen >> 16) & 0xff;
kl[2] = (keylen >> 8) & 0xff;
kl[3] = keylen & 0xff;
oklen.length = 4;
oklen.data = kl;
oklen.type = V_ASN1_OCTET_STRING;
oklen.flags = 0;
ecsi.keyInfo = kekalg;
ecsi.entityUInfo = ukm;
ecsi.suppPubInfo = &oklen;
intsi.pecsi = &ecsi;
return ASN1_item_i2d(intsi.a, pder, ASN1_ITEM_rptr(CMS_SharedInfo));
}

197
cms/lib/cms_att.c Normal file
View file

@ -0,0 +1,197 @@
/* crypto/cms/cms_att.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "cms.h"
#include "cms_lcl.h"
/* CMS SignedData Attribute utilities */
int CMS_signed_get_attr_count(const CMS_SignerInfo *si)
{
return X509at_get_attr_count(si->signedAttrs);
}
int CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, int lastpos)
{
return X509at_get_attr_by_NID(si->signedAttrs, nid, lastpos);
}
int CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
int lastpos)
{
return X509at_get_attr_by_OBJ(si->signedAttrs, obj, lastpos);
}
X509_ATTRIBUTE *CMS_signed_get_attr(const CMS_SignerInfo *si, int loc)
{
return X509at_get_attr(si->signedAttrs, loc);
}
X509_ATTRIBUTE *CMS_signed_delete_attr(CMS_SignerInfo *si, int loc)
{
return X509at_delete_attr(si->signedAttrs, loc);
}
int CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
{
if (X509at_add1_attr(&si->signedAttrs, attr))
return 1;
return 0;
}
int CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si,
const ASN1_OBJECT *obj, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_OBJ(&si->signedAttrs, obj, type, bytes, len))
return 1;
return 0;
}
int CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si,
int nid, int type, const void *bytes, int len)
{
if (X509at_add1_attr_by_NID(&si->signedAttrs, nid, type, bytes, len))
return 1;
return 0;
}
int CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si,
const char *attrname, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_txt(&si->signedAttrs, attrname, type, bytes, len))
return 1;
return 0;
}
void *CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
int lastpos, int type)
{
return X509at_get0_data_by_OBJ(si->signedAttrs, oid, lastpos, type);
}
int CMS_unsigned_get_attr_count(const CMS_SignerInfo *si)
{
return X509at_get_attr_count(si->unsignedAttrs);
}
int CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid,
int lastpos)
{
return X509at_get_attr_by_NID(si->unsignedAttrs, nid, lastpos);
}
int CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, ASN1_OBJECT *obj,
int lastpos)
{
return X509at_get_attr_by_OBJ(si->unsignedAttrs, obj, lastpos);
}
X509_ATTRIBUTE *CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc)
{
return X509at_get_attr(si->unsignedAttrs, loc);
}
X509_ATTRIBUTE *CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc)
{
return X509at_delete_attr(si->unsignedAttrs, loc);
}
int CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
{
if (X509at_add1_attr(&si->unsignedAttrs, attr))
return 1;
return 0;
}
int CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si,
const ASN1_OBJECT *obj, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, type, bytes, len))
return 1;
return 0;
}
int CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si,
int nid, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_NID(&si->unsignedAttrs, nid, type, bytes, len))
return 1;
return 0;
}
int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
const char *attrname, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_txt(&si->unsignedAttrs, attrname,
type, bytes, len))
return 1;
return 0;
}
void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
int lastpos, int type)
{
return X509at_get0_data_by_OBJ(si->unsignedAttrs, oid, lastpos, type);
}
/* Specific attribute cases */

134
cms/lib/cms_cd.c Normal file
View file

@ -0,0 +1,134 @@
/* crypto/cms/cms_cd.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "cms.h"
#include <openssl/bio.h>
#ifndef OPENSSL_NO_COMP
# include <openssl/comp.h>
#endif
#include "cms_lcl.h"
DECLARE_ASN1_ITEM(CMS_CompressedData)
#ifdef ZLIB
/* CMS CompressedData Utilities */
CMS_ContentInfo *cms_CompressedData_create(int comp_nid)
{
CMS_ContentInfo *cms;
CMS_CompressedData *cd;
/*
* Will need something cleverer if there is ever more than one
* compression algorithm or parameters have some meaning...
*/
if (comp_nid != NID_zlib_compression) {
CMSerr(CMS_F_CMS_COMPRESSEDDATA_CREATE,
CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
return NULL;
}
cms = CMS_ContentInfo_new();
if (!cms)
return NULL;
cd = M_ASN1_new_of(CMS_CompressedData);
if (!cd)
goto err;
cms->contentType = OBJ_nid2obj(NID_id_smime_ct_compressedData);
cms->d.compressedData = cd;
cd->version = 0;
X509_ALGOR_set0(cd->compressionAlgorithm,
OBJ_nid2obj(NID_zlib_compression), V_ASN1_UNDEF, NULL);
cd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data);
return cms;
err:
if (cms)
CMS_ContentInfo_free(cms);
return NULL;
}
BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms)
{
CMS_CompressedData *cd;
ASN1_OBJECT *compoid;
if (OBJ_obj2nid(cms->contentType) != NID_id_smime_ct_compressedData) {
CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO,
CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA);
return NULL;
}
cd = cms->d.compressedData;
X509_ALGOR_get0(&compoid, NULL, NULL, cd->compressionAlgorithm);
if (OBJ_obj2nid(compoid) != NID_zlib_compression) {
CMSerr(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO,
CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
return NULL;
}
return BIO_new(BIO_f_zlib());
}
#endif

145
cms/lib/cms_dd.c Normal file
View file

@ -0,0 +1,145 @@
/* crypto/cms/cms_dd.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "cms.h"
#include "cms_lcl.h"
DECLARE_ASN1_ITEM(CMS_DigestedData)
/* CMS DigestedData Utilities */
CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md)
{
CMS_ContentInfo *cms;
CMS_DigestedData *dd;
cms = CMS_ContentInfo_new();
if (!cms)
return NULL;
dd = M_ASN1_new_of(CMS_DigestedData);
if (!dd)
goto err;
cms->contentType = OBJ_nid2obj(NID_pkcs7_digest);
cms->d.digestedData = dd;
dd->version = 0;
dd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data);
cms_DigestAlgorithm_set(dd->digestAlgorithm, md);
return cms;
err:
if (cms)
CMS_ContentInfo_free(cms);
return NULL;
}
BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms)
{
CMS_DigestedData *dd;
dd = cms->d.digestedData;
return cms_DigestAlgorithm_init_bio(dd->digestAlgorithm);
}
int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify)
{
EVP_MD_CTX mctx;
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int mdlen;
int r = 0;
CMS_DigestedData *dd;
EVP_MD_CTX_init(&mctx);
dd = cms->d.digestedData;
if (!cms_DigestAlgorithm_find_ctx(&mctx, chain, dd->digestAlgorithm))
goto err;
if (EVP_DigestFinal_ex(&mctx, md, &mdlen) <= 0)
goto err;
if (verify) {
if (mdlen != (unsigned int)dd->digest->length) {
CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL,
CMS_R_MESSAGEDIGEST_WRONG_LENGTH);
goto err;
}
if (memcmp(md, dd->digest->data, mdlen))
CMSerr(CMS_F_CMS_DIGESTEDDATA_DO_FINAL,
CMS_R_VERIFICATION_FAILURE);
else
r = 1;
} else {
if (!ASN1_STRING_set(dd->digest, md, mdlen))
goto err;
r = 1;
}
err:
EVP_MD_CTX_cleanup(&mctx);
return r;
}

264
cms/lib/cms_enc.c Normal file
View file

@ -0,0 +1,264 @@
/* crypto/cms/cms_enc.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "cms.h"
#include <openssl/rand.h>
#include "cms_lcl.h"
/* CMS EncryptedData Utilities */
DECLARE_ASN1_ITEM(CMS_EncryptedData)
/* Return BIO based on EncryptedContentInfo and key */
BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
{
BIO *b;
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *ciph;
X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
unsigned char *tkey = NULL;
size_t tkeylen = 0;
int ok = 0;
int enc, keep_key = 0;
enc = ec->cipher ? 1 : 0;
b = BIO_new(BIO_f_cipher());
if (!b) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
return NULL;
}
BIO_get_cipher_ctx(b, &ctx);
if (enc) {
ciph = ec->cipher;
/*
* If not keeping key set cipher to NULL so subsequent calls decrypt.
*/
if (ec->key)
ec->cipher = NULL;
} else {
ciph = EVP_get_cipherbyobj(calg->algorithm);
if (!ciph) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
goto err;
}
}
if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_CIPHER_INITIALISATION_ERROR);
goto err;
}
if (enc) {
int ivlen;
calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
/* Generate a random IV if we need one */
ivlen = EVP_CIPHER_CTX_iv_length(ctx);
if (ivlen > 0) {
if (RAND_bytes(iv, ivlen) <= 0)
goto err;
piv = iv;
}
} else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
tkeylen = EVP_CIPHER_CTX_key_length(ctx);
/* Generate random session key */
if (!enc || !ec->key) {
tkey = OPENSSL_malloc(tkeylen);
if (!tkey) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
goto err;
}
if (!ec->key) {
ec->key = tkey;
ec->keylen = tkeylen;
tkey = NULL;
if (enc)
keep_key = 1;
else
ERR_clear_error();
}
if (ec->keylen != tkeylen) {
/* If necessary set key length */
if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
/*
* Only reveal failure if debugging so we don't leak information
* which may be useful in MMA.
*/
if (enc || ec->debug) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_INVALID_KEY_LENGTH);
goto err;
} else {
/* Use random key */
OPENSSL_cleanse(ec->key, ec->keylen);
OPENSSL_free(ec->key);
ec->key = tkey;
ec->keylen = tkeylen;
tkey = NULL;
ERR_clear_error();
}
}
}
if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_CIPHER_INITIALISATION_ERROR);
goto err;
}
if (enc) {
calg->parameter = ASN1_TYPE_new();
if (calg->parameter == NULL) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
/* If parameter type not set omit parameter */
if (calg->parameter->type == V_ASN1_UNDEF) {
ASN1_TYPE_free(calg->parameter);
calg->parameter = NULL;
}
}
ok = 1;
err:
if (ec->key && (!keep_key || !ok)) {
OPENSSL_cleanse(ec->key, ec->keylen);
OPENSSL_free(ec->key);
ec->key = NULL;
}
if (tkey) {
OPENSSL_cleanse(tkey, tkeylen);
OPENSSL_free(tkey);
}
if (ok)
return b;
BIO_free(b);
return NULL;
}
int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen)
{
ec->cipher = cipher;
if (key) {
ec->key = OPENSSL_malloc(keylen);
if (!ec->key)
return 0;
memcpy(ec->key, key, keylen);
}
ec->keylen = keylen;
if (cipher)
ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
return 1;
}
int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
const unsigned char *key, size_t keylen)
{
CMS_EncryptedContentInfo *ec;
if (!key || !keylen) {
CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY);
return 0;
}
if (ciph) {
cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
if (!cms->d.encryptedData) {
CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE);
return 0;
}
cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
cms->d.encryptedData->version = 0;
} else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA);
return 0;
}
ec = cms->d.encryptedData->encryptedContentInfo;
return cms_EncryptedContent_init(ec, ciph, key, keylen);
}
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedData *enc = cms->d.encryptedData;
if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
enc->version = 2;
return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
}

977
cms/lib/cms_env.c Normal file
View file

@ -0,0 +1,977 @@
/* crypto/cms/cms_env.c */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "cms.h"
#include <openssl/rand.h>
#include <openssl/aes.h>
#include "cms_lcl.h"
#include "asn1_locl.h"
extern int libressl_pkey_ctrl(EVP_PKEY *, int, long, void *);
extern int libressl_pkey_ctx_ctrl(EVP_PKEY_CTX *, int, int, int, int, void *);
/* CMS EnvelopedData Utilities */
DECLARE_ASN1_ITEM(CMS_EnvelopedData)
DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
DECLARE_STACK_OF(CMS_RecipientInfo)
CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
{
if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
CMSerr(CMS_F_CMS_GET0_ENVELOPED,
CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
return NULL;
}
return cms->d.envelopedData;
}
static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
{
if (cms->d.other == NULL) {
cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
if (!cms->d.envelopedData) {
CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE);
return NULL;
}
cms->d.envelopedData->version = 0;
cms->d.envelopedData->encryptedContentInfo->contentType =
OBJ_nid2obj(NID_pkcs7_data);
ASN1_OBJECT_free(cms->contentType);
cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
return cms->d.envelopedData;
}
return cms_get0_enveloped(cms);
}
int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
{
EVP_PKEY *pkey;
int i;
if (ri->type == CMS_RECIPINFO_TRANS)
pkey = ri->d.ktri->pkey;
else if (ri->type == CMS_RECIPINFO_AGREE) {
EVP_PKEY_CTX *pctx = ri->d.kari->pctx;