diff --git a/lib/libspl/crypto.c b/lib/libspl/crypto.c index 6bca41a24096..79a751b13f68 100644 --- a/lib/libspl/crypto.c +++ b/lib/libspl/crypto.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "sha1.h" @@ -138,5 +141,115 @@ int crypto_pass2key(unsigned char *keydata, size_t keydatalen, } +/* OpenSolaris */ - +/* + * Read file into buffer. Used to read raw key data or initialization + * vector data. Buffer must be freed by caller using free(). + * + * If file is a regular file, entire file is read and dlen is set + * to the number of bytes read. Otherwise, dlen should first be set + * to the number of bytes requested and will be reset to actual number + * of bytes returned. + * + * Return 0 on success and errno on error. + */ +int +pkcs11_read_data(char *filename, void **dbuf, size_t *dlen) +{ + int fd = -1; + struct stat statbuf; + boolean_t plain_file; + void *filebuf = NULL; + size_t filesize = 0; + int ret = 0; + + if (filename == NULL || dbuf == NULL || dlen == NULL) + return (-1); + + if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) { + ret = errno; + goto error; + } + + if (fstat(fd, &statbuf) == -1) { + ret = errno; + goto error; + } + + if (S_ISREG(statbuf.st_mode)) { + /* read the entire regular file */ + filesize = statbuf.st_size; + plain_file = B_TRUE; + } else { + /* read requested bytes from special file */ + filesize = *dlen; + plain_file = B_FALSE; + } + + if (filesize == 0) { + /* + * for decrypt this is an error; for digest this is ok; + * make it ok here but also set dbuf = NULL and dlen = 0 + * to indicate there was no data to read and caller can + * retranslate that to an error if it wishes. + */ + (void) close(fd); + *dbuf = NULL; + *dlen = 0; + return (0); + } + + if ((filebuf = malloc(filesize)) == NULL) { + ret = errno; + goto error; + } + + if (plain_file) { + /* either it got read or it didn't */ + if (read(fd, filebuf, filesize) != filesize) { + ret = errno; + goto error; + } + } else { + /* reading from special file may need some coaxing */ + char *marker = (char *)filebuf; + size_t left = filesize; + ssize_t nread; + + for (/* */; left > 0; marker += nread, left -= nread) { + /* keep reading it's going well */ + nread = read(fd, marker, left); + if (nread > 0 || (nread == 0 && errno == EINTR)) { + errno = 0; + continue; + } + + /* might have to be good enough for caller */ + if (nread == 0 && errno == EAGAIN) + break; + + /* anything else is an error */ + if (errno) { + ret = errno; + goto error; + } + } + /* reset to actual number of bytes read */ + filesize -= left; + } + + (void) close(fd); + *dbuf = filebuf; + *dlen = filesize; + return (0); + +error: + if (filebuf != NULL) { + free(filebuf); + } + if (fd != -1) + (void) close(fd); + + return (ret); +} diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index 064276cba26f..1523d75f8a52 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -252,6 +252,7 @@ int crypto_pass2key(unsigned char *keydata, size_t keydatalen, void *salt, size_t saltlen, size_t desired_keylen, void **out_keydata, size_t *out_keylen); +int pkcs11_read_data(char *filename, void **dbuf, size_t *dlen); /* @@ -726,7 +727,6 @@ key_hdl_to_zc(libzfs_handle_t *hdl, zfs_handle_t *zhp, char *keysource, * Note that pkcs11_read_data allocates memory with malloc * that we need to free. */ -#if 0 // FIXME keydatalen = keylen; ret = pkcs11_read_data(&(uri[7]), (void **)&keydata, &keydatalen); @@ -736,7 +736,6 @@ key_hdl_to_zc(libzfs_handle_t *hdl, zfs_handle_t *zhp, char *keysource, errno = ret; return (-1); } -#endif break; case KEY_LOCATOR_PKCS11_URI: