Hi Claudio.
FYI, I've added some support for https. Not sure if this might be
useful, but here is the code for ta_parse_buffer.
I´ve also modified tal_parse to display a warn message instead of
exiting on invalid basename.
Regards,
Alexandre Hamada
static int
https_uri_parse(const char **hostp, size_t *hostsz,
const char **pathp, size_t *pathsz,
enum rtype *rtypep, const char *uri)
{
const char *host, *path;
size_t sz;
/* Initialise all output values to NULL or 0. */
if (hostsz != NULL)
*hostsz = 0;
if (pathsz != NULL)
*pathsz = 0;
if (hostp != NULL)
*hostp = 0;
if (pathp != NULL)
*pathp = 0;
if (rtypep != NULL)
*rtypep = RTYPE_EOF;
/* Case-insensitive https URI. */
if (strncasecmp(uri, "https://", 8)) {
warnx("%s: not using https schema", uri);
return 0;
}
/* Parse the non-zero-length hostname. */
host = uri + 8;
if ((path = strchr(host, '/')) == NULL) {
warnx("%s: missing https path", uri);
return 0;
} else if (path == host) {
warnx("%s: zero-length https path", uri);
return 0;
}
if (hostp != NULL)
*hostp = host;
if (hostsz != NULL)
*hostsz = path - host;
path++;
sz = strlen(path);
if (pathp != NULL)
*pathp = path;
if (pathsz != NULL)
*pathsz = sz;
if (rtypep != NULL && sz > 4) {
if (strcasecmp(path + sz - 4, ".roa") == 0)
*rtypep = RTYPE_ROA;
else if (strcasecmp(path + sz - 4, ".mft") == 0)
*rtypep = RTYPE_MFT;
else if (strcasecmp(path + sz - 4, ".cer") == 0)
*rtypep = RTYPE_CER;
else if (strcasecmp(path + sz - 4, ".crl") == 0)
*rtypep = RTYPE_CRL;
}
return 1;
}
/*
* Inner function for parsing RFC 7730 from a buffer.
* Returns a valid pointer on success, NULL otherwise.
* The pointer must be freed with tal_free().
*/
static struct tal *
tal_parse_buffer(const char *fn, char *buf)
{
char *nl, *line;
unsigned char *b64 = NULL;
size_t sz;
int rc = 0, b64sz;
struct tal *tal = NULL;
enum rtype rp;
EVP_PKEY *pkey = NULL;
if ((tal = calloc(1, sizeof(struct tal))) == NULL)
err(EXIT_FAILURE, NULL);
/* Begin with the URI section, comment section already removed. */
while ((nl = strchr(buf, '\n')) != NULL) {
line = buf;
*nl = '\0';
/* advance buffer to next line */
buf = nl + 1;
/* Zero-length line is end of section. */
if (*line == '\0')
break;
/* Append to list of URIs. */
tal->uri = reallocarray(tal->uri,
tal->urisz + 1, sizeof(char *));
if (tal->uri == NULL)
err(EXIT_FAILURE, NULL);
tal->uri[tal->urisz] = strdup(line);
if (tal->uri[tal->urisz] == NULL)
err(EXIT_FAILURE, NULL);
tal->urisz++;
/* Make sure we're a proper rsync/https URI. */
if (strncasecmp(line, "https://", 8) == 0) {
if (!https_uri_parse(NULL, NULL, NULL, NULL, &rp, line)) {
warnx("%s: RFC 8630 section 2.2: "
"failed to parse URL: %s", fn, line);
goto out;
}
} else if (!rsync_uri_parse(NULL, NULL, NULL, NULL, NULL, NULL,
&rp, line)) {
warnx("%s: RFC 8630 section 2.2: "
"failed to parse URL: %s", fn, line);
goto out;
}
if (rp != RTYPE_CER) {
warnx("%s: RFC 7730 section 2.1: "
"not a certificate URL: %s", fn, line);
goto out;
}
}
if (tal->urisz == 0) {
warnx("%s: no URIs in manifest part", fn);
goto out;
} else if (tal->urisz > 1)
warnx("%s: multiple URIs: using the first", fn);
sz = strlen(buf);
if (sz == 0) {
warnx("%s: RFC 7730 section 2.1: subjectPublicKeyInfo: "
"zero-length public key", fn);
goto out;
}
/* Now the BASE64-encoded public key. */
sz = ((sz + 2) / 3) * 4 + 1;
if ((b64 = malloc(sz)) == NULL)
err(EXIT_FAILURE, NULL);
if ((b64sz = b64_pton(buf, b64, sz)) < 0)
errx(EXIT_FAILURE, "b64_pton");
tal->pkey = b64;
tal->pkeysz = b64sz;
/* Make sure it's a valid public key. */
pkey = d2i_PUBKEY(NULL, (const unsigned char **)&b64, b64sz);
if (pkey == NULL) {
cryptowarnx("%s: RFC 7730 section 2.1: subjectPublicKeyInfo: "
"failed public key parse", fn);
goto out;
}
rc = 1;
out:
if (rc == 0) {
tal_free(tal);
tal = NULL;
}
EVP_PKEY_free(pkey);
return tal;
}
/*
* Parse a TAL from a file conformant to RFC 7730.
* Returns the encoded data or NULL on failure.
* Failure can be any number of things: failure to open file, allocate
* memory, bad syntax, etc.
*/
struct tal *
tal_parse(const char *fn, char *buf)
{
struct tal *p;
char *d;
size_t dlen;
p = tal_parse_buffer(fn, buf);
if (p != NULL) {
/* extract the TAL basename (without .tal suffix) */
d = basename((char*)fn);
if (d == NULL) {
warnx("%s: basename", fn);
} else {
dlen = strlen(d);
if (strcasecmp(d + dlen - 4, ".tal") == 0)
dlen -= 4;
if ((p->descr = malloc(dlen + 1)) == NULL)
err(EXIT_FAILURE, NULL);
memcpy(p->descr, d, dlen);
p->descr[dlen] = 0;
}
}
return p;
}
On 05/11/2019 11:01, Alexandre Hamada wrote:
Hi Claudio,
I was testing some tal files, and when it contains an https url (RFC
8630), it generates a segmentation fault.
Thus, I would like to suggest adding the following on tal_parse/tal_free.
Example:
https://rir.docker/ta/ta.cer
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoFVWio0auchdC1mCbp4N
pSG9b43tXDIIOHHsc/6fTg0wdFdX68qHFYAwTlXVriXs5j0WmB8DZ1qiE4nyYfEj
kVIU6bVbz8WZ03BpajGO1AfbasBdbAr4SWjl8YCyCFjfojij2SnH/lbjxca5mSa0
wJAT4LEG/B4kMROcKRSebTCi8iDxMYha1GFFXBD9ze9qpEoUE3ZobQfITMNd8xZx
mZyg6bXXnT8qj7m5IrCs7dD4qrhjPTKbxwlpXFlS4pNdh9p9H/gFHxF7SbOLIq4m
2rBQKNCMzvFnFgWJyM2QqiCb89WJf6kvyBjMbh7h/HygaXy8SuXUprExudQy8OZp
xwIDAQAB
Regards,
Alexandre Hamada
@@ -142,18 +142,19 @@ tal_parse(const char *fn, char *buf)
p = tal_parse_buffer(fn, buf);
- /* extract the TAL basename (without .tal suffix) */
- d = basename((char*)fn);
- if (d == NULL)
- err(EXIT_FAILURE, "%s: basename", fn);
- dlen = strlen(d);
- if (strcasecmp(d + dlen - 4, ".tal") == 0)
- dlen -= 4;
- if ((p->descr = malloc(dlen + 1)) == NULL)
- err(EXIT_FAILURE, NULL);
- memcpy(p->descr, d, dlen);
- p->descr[dlen] = 0;
-
+ if(p != NULL) {
+ /* extract the TAL basename (without .tal suffix) */
+ d = basename((char*)fn);
+ if (d == NULL)
+ err(EXIT_FAILURE, "%s: basename", fn);
+ dlen = strlen(d);
+ if (strcasecmp(d + dlen - 4, ".tal") == 0)
+ dlen -= 4;
+ if ((p->descr = malloc(dlen + 1)) == NULL)
+ err(EXIT_FAILURE, NULL);
+ memcpy(p->descr, d, dlen);
+ p->descr[dlen] = 0;
+ }
return p;
}
@@ -231,9 +232,15 @@ tal_free(struct tal *p)
for (i = 0; i < p->urisz; i++)
free(p->uri[i]);
- free(p->pkey);
- free(p->uri);
- free(p->descr);
+ if (p->pkey != NULL) {
+ free(p->pkey);
+ }
+ if (p->uri != NULL) {
+ free(p->uri);
+ }
+ if (p->descr != NULL) {
+ free(p->descr);
+ }
free(p);
}