| /* |
| * 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 <nettle/asn1.h> |
| |
| #include "qemu/osdep.h" |
| #include "qapi/error.h" |
| #include "rsakey.h" |
| |
| static bool DumpMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) |
| { |
| mpi->data = g_memdup2(i->data, i->length); |
| mpi->len = i->length; |
| return true; |
| } |
| |
| static bool GetMPI(struct asn1_der_iterator *i, QCryptoAkCipherMPI *mpi) |
| { |
| if (asn1_der_iterator_next(i) != ASN1_ITERATOR_PRIMITIVE || |
| i->type != ASN1_INTEGER) { |
| return false; |
| } |
| return DumpMPI(i, mpi); |
| } |
| |
| /** |
| * 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_nettle_rsa_private_key_parse( |
| const uint8_t *key, size_t keylen, Error **errp) |
| { |
| QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); |
| struct asn1_der_iterator i; |
| uint32_t version; |
| int tag; |
| |
| /* Parse entire struct */ |
| if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || |
| i.type != ASN1_SEQUENCE || |
| asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || |
| i.type != ASN1_INTEGER || |
| !asn1_der_get_uint32(&i, &version) || |
| version > 1 || |
| !GetMPI(&i, &rsa->n) || |
| !GetMPI(&i, &rsa->e) || |
| !GetMPI(&i, &rsa->d) || |
| !GetMPI(&i, &rsa->p) || |
| !GetMPI(&i, &rsa->q) || |
| !GetMPI(&i, &rsa->dp) || |
| !GetMPI(&i, &rsa->dq) || |
| !GetMPI(&i, &rsa->u)) { |
| goto error; |
| } |
| |
| if (version == 1) { |
| tag = asn1_der_iterator_next(&i); |
| /** |
| * 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 (tag == ASN1_ITERATOR_END) { |
| return rsa; |
| } |
| if (tag != ASN1_ITERATOR_CONSTRUCTED || |
| i.type != ASN1_SEQUENCE) { |
| goto error; |
| } |
| } |
| |
| if (asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { |
| goto error; |
| } |
| |
| return rsa; |
| |
| error: |
| error_setg(errp, "Failed to parse RSA private key"); |
| qcrypto_akcipher_rsakey_free(rsa); |
| return NULL; |
| } |
| |
| /** |
| * RsaPubKey ::= SEQUENCE { |
| * n INTEGER |
| * e INTEGER |
| * } |
| */ |
| static QCryptoAkCipherRSAKey *qcrypto_nettle_rsa_public_key_parse( |
| const uint8_t *key, size_t keylen, Error **errp) |
| { |
| |
| QCryptoAkCipherRSAKey *rsa = g_new0(QCryptoAkCipherRSAKey, 1); |
| struct asn1_der_iterator i; |
| |
| if (asn1_der_iterator_first(&i, keylen, key) != ASN1_ITERATOR_CONSTRUCTED || |
| i.type != ASN1_SEQUENCE || |
| asn1_der_decode_constructed_last(&i) != ASN1_ITERATOR_PRIMITIVE || |
| !DumpMPI(&i, &rsa->n) || |
| !GetMPI(&i, &rsa->e) || |
| asn1_der_iterator_next(&i) != ASN1_ITERATOR_END) { |
| goto error; |
| } |
| |
| return rsa; |
| |
| error: |
| error_setg(errp, "Failed to parse RSA public key"); |
| 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_nettle_rsa_private_key_parse(key, keylen, errp); |
| |
| case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC: |
| return qcrypto_nettle_rsa_public_key_parse(key, keylen, errp); |
| |
| default: |
| error_setg(errp, "Unknown key type: %d", type); |
| return NULL; |
| } |
| } |