| /* |
| * QEMU Crypto akcipher algorithms |
| * |
| * Copyright (c) 2022 Bytedance |
| * Author: lei he <helei.sig11@bytedance.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| * |
| */ |
| |
| #include "der.h" |
| #include "rsakey.h" |
| |
| static int extract_mpi(void *ctx, const uint8_t *value, |
| size_t vlen, Error **errp) |
| { |
| QCryptoAkCipherMPI *mpi = (QCryptoAkCipherMPI *)ctx; |
| if (vlen == 0) { |
| error_setg(errp, "Empty mpi field"); |
| return -1; |
| } |
| mpi->data = g_memdup2(value, vlen); |
| mpi->len = vlen; |
| return 0; |
| } |
| |
| static int extract_version(void *ctx, const uint8_t *value, |
| size_t vlen, Error **errp) |
| { |
| uint8_t *version = (uint8_t *)ctx; |
| if (vlen != 1 || *value > 1) { |
| error_setg(errp, "Invalid rsakey version"); |
| return -1; |
| } |
| *version = *value; |
| return 0; |
| } |
| |
| static int extract_seq_content(void *ctx, const uint8_t *value, |
| size_t vlen, Error **errp) |
| { |
| const uint8_t **content = (const uint8_t **)ctx; |
| if (vlen == 0) { |
| error_setg(errp, "Empty sequence"); |
| return -1; |
| } |
| *content = value; |
| return 0; |
| } |
| |
| /** |
| * |
| * RsaPubKey ::= SEQUENCE { |
| * n INTEGER |
| * e INTEGER |
| * } |
| */ |
| static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_public_key_parse( |
| const uint8_t *key, size_t keylen, Error **errp) |
| { |
| QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); |
| const uint8_t *seq; |
| size_t seq_length; |
| int decode_ret; |
| |
| decode_ret = qcrypto_der_decode_seq(&key, &keylen, |
| extract_seq_content, &seq, errp); |
| if (decode_ret < 0 || keylen != 0) { |
| goto error; |
| } |
| seq_length = decode_ret; |
| |
| if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, |
| &rsa->n, errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, |
| &rsa->e, errp) < 0) { |
| goto error; |
| } |
| if (seq_length != 0) { |
| error_setg(errp, "Invalid RSA public key"); |
| goto error; |
| } |
| |
| return rsa; |
| |
| error: |
| qcrypto_akcipher_rsakey_free(rsa); |
| return NULL; |
| } |
| |
| /** |
| * RsaPrivKey ::= SEQUENCE { |
| * version INTEGER |
| * n INTEGER |
| * e INTEGER |
| * d INTEGER |
| * p INTEGER |
| * q INTEGER |
| * dp INTEGER |
| * dq INTEGER |
| * u INTEGER |
| * otherPrimeInfos OtherPrimeInfos OPTIONAL |
| * } |
| */ |
| static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_private_key_parse( |
| const uint8_t *key, size_t keylen, Error **errp) |
| { |
| QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); |
| uint8_t version; |
| const uint8_t *seq; |
| int decode_ret; |
| size_t seq_length; |
| |
| decode_ret = qcrypto_der_decode_seq(&key, &keylen, extract_seq_content, |
| &seq, errp); |
| if (decode_ret < 0 || keylen != 0) { |
| goto error; |
| } |
| seq_length = decode_ret; |
| |
| decode_ret = qcrypto_der_decode_int(&seq, &seq_length, extract_version, |
| &version, errp); |
| |
| if (qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, |
| &rsa->n, errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, |
| &rsa->e, errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, |
| &rsa->d, errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->p, |
| errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->q, |
| errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dp, |
| errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->dq, |
| errp) < 0 || |
| qcrypto_der_decode_int(&seq, &seq_length, extract_mpi, &rsa->u, |
| errp) < 0) { |
| goto error; |
| } |
| |
| /** |
| * According to the standard, otherPrimeInfos must be present for version 1. |
| * There is no strict verification here, this is to be compatible with |
| * the unit test of the kernel. TODO: remove this until linux kernel's |
| * unit-test is fixed. |
| */ |
| if (version == 1 && seq_length != 0) { |
| if (qcrypto_der_decode_seq(&seq, &seq_length, NULL, NULL, errp) < 0) { |
| goto error; |
| } |
| if (seq_length != 0) { |
| goto error; |
| } |
| return rsa; |
| } |
| if (seq_length != 0) { |
| error_setg(errp, "Invalid RSA private key"); |
| goto error; |
| } |
| |
| return rsa; |
| |
| error: |
| qcrypto_akcipher_rsakey_free(rsa); |
| return NULL; |
| } |
| |
| QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse( |
| QCryptoAkCipherKeyType type, const uint8_t *key, |
| size_t keylen, Error **errp) |
| { |
| switch (type) { |
| case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE: |
| return qcrypto_builtin_rsa_private_key_parse(key, keylen, errp); |
| |
| case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC: |
| return qcrypto_builtin_rsa_public_key_parse(key, keylen, errp); |
| |
| default: |
| error_setg(errp, "Unknown key type: %d", type); |
| return NULL; |
| } |
| } |