| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141 |
- /*
- * Embedded Linux library
- *
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <time.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <stdio.h>
- #include <strings.h>
- #include "useful.h"
- #include "private.h"
- #include "tls.h"
- #include "checksum.h"
- #include "cipher.h"
- #include "random.h"
- #include "queue.h"
- #include "pem.h"
- #include "pem-private.h"
- #include "asn1-private.h"
- #include "cert.h"
- #include "cert-private.h"
- #include "tls-private.h"
- #include "key.h"
- #include "strv.h"
- #include "missing.h"
- #include "string.h"
- bool tls10_prf(const void *secret, size_t secret_len,
- const char *label,
- const void *seed, size_t seed_len,
- uint8_t *out, size_t out_len)
- {
- uint8_t p_hash2[out_len];
- uint8_t l_s1 = (secret_len + 1) / 2;
- unsigned int i;
- /*
- * RFC2246 section 5:
- * S1 and S2 are the two halves of the secret, and each is the same
- * length. S1 is taken from the first half of the secret, S2 from the
- * second half. Their length is created by rounding up the length of
- * the overall secret, divided by two; thus, if the original secret is
- * an odd number of bytes long, the last byte of S1 will be the same as
- * the first byte of S2.
- */
- if (!tls12_prf(L_CHECKSUM_MD5, secret, l_s1,
- label, seed, seed_len,
- out, out_len))
- return false;
- if (secret_len > 0)
- secret += secret_len - l_s1;
- if (!tls12_prf(L_CHECKSUM_SHA1, secret, l_s1,
- label, seed, seed_len,
- p_hash2, out_len))
- return false;
- for (i = 0; i < out_len; i++)
- out[i] ^= p_hash2[i];
- return true;
- }
- bool tls12_prf(enum l_checksum_type type,
- const void *secret, size_t secret_len,
- const char *label,
- const void *seed, size_t seed_len,
- uint8_t *out, size_t out_len)
- {
- struct l_checksum *hmac = l_checksum_new_hmac(type, secret, secret_len);
- size_t a_len, chunk_len, prfseed_len = strlen(label) + seed_len;
- uint8_t a[64 + prfseed_len], prfseed[prfseed_len];
- if (!hmac)
- return false;
- /* Generate the hash seed or A(0) as label + seed */
- memcpy(prfseed, label, strlen(label));
- memcpy(prfseed + strlen(label), seed, seed_len);
- memcpy(a, prfseed, prfseed_len);
- a_len = prfseed_len;
- while (out_len) {
- /* Generate A(i) */
- l_checksum_reset(hmac);
- l_checksum_update(hmac, a, a_len);
- a_len = l_checksum_get_digest(hmac, a, sizeof(a));
- /* Append seed & generate output */
- memcpy(a + a_len, prfseed, prfseed_len);
- l_checksum_reset(hmac);
- l_checksum_update(hmac, a, a_len + prfseed_len);
- chunk_len = l_checksum_get_digest(hmac, out, out_len);
- out += chunk_len;
- out_len -= chunk_len;
- }
- l_checksum_free(hmac);
- return true;
- }
- static bool tls_prf_get_bytes(struct l_tls *tls,
- const void *secret, size_t secret_len,
- const char *label,
- const void *seed, size_t seed_len,
- uint8_t *buf, size_t len)
- {
- if (tls->negotiated_version >= L_TLS_V12)
- return tls12_prf(tls->prf_hmac->l_id,
- secret, secret_len, label,
- seed, seed_len, buf, len);
- return tls10_prf(secret, secret_len, label, seed, seed_len,
- buf, len);
- }
- LIB_EXPORT bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret,
- const char *label, uint8_t *buf, size_t len)
- {
- uint8_t seed[64];
- bool r;
- if (unlikely(!tls || !tls->prf_hmac))
- return false;
- memcpy(seed + 0, tls->pending.client_random, 32);
- memcpy(seed + 32, tls->pending.server_random, 32);
- if (use_master_secret)
- r = tls_prf_get_bytes(tls, tls->pending.master_secret, 48,
- label, seed, 64, buf, len);
- else
- r = tls_prf_get_bytes(tls, "", 0, label, seed, 64, buf, len);
- explicit_bzero(seed, 64);
- return r;
- }
- static void tls_write_random(uint8_t *buf)
- {
- l_put_be32(time(NULL), buf);
- l_getrandom(buf + 4, 28);
- }
- static void tls_drop_handshake_hash(struct l_tls *tls,
- enum handshake_hash_type hash)
- {
- if (tls->handshake_hash[hash]) {
- l_checksum_free(tls->handshake_hash[hash]);
- tls->handshake_hash[hash] = NULL;
- }
- }
- static void tls_reset_handshake(struct l_tls *tls)
- {
- enum handshake_hash_type hash;
- explicit_bzero(tls->pending.key_block, sizeof(tls->pending.key_block));
- if (tls->pending.cipher_suite &&
- tls->pending.cipher_suite->key_xchg->free_params)
- tls->pending.cipher_suite->key_xchg->free_params(tls);
- l_cert_free(tls->peer_cert);
- l_key_free(tls->peer_pubkey);
- tls->peer_cert = NULL;
- tls->peer_pubkey = NULL;
- tls->peer_pubkey_size = 0;
- tls->negotiated_curve = NULL;
- tls->negotiated_ff_group = NULL;
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
- tls_drop_handshake_hash(tls, hash);
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START);
- tls->cert_requested = 0;
- tls->cert_sent = 0;
- }
- static void tls_cleanup_handshake(struct l_tls *tls)
- {
- explicit_bzero(tls->pending.client_random, 32);
- explicit_bzero(tls->pending.server_random, 32);
- explicit_bzero(tls->pending.master_secret, 48);
- }
- static bool tls_change_cipher_spec(struct l_tls *tls, bool txrx,
- const char **error)
- {
- struct tls_bulk_encryption_algorithm *enc;
- struct tls_mac_algorithm *mac;
- int key_offset;
- static char error_buf[200];
- if (tls->cipher_type[txrx] == TLS_CIPHER_AEAD) {
- if (tls->aead_cipher[txrx]) {
- l_aead_cipher_free(tls->aead_cipher[txrx]);
- tls->aead_cipher[txrx] = NULL;
- }
- } else {
- if (tls->cipher[txrx]) {
- l_cipher_free(tls->cipher[txrx]);
- tls->cipher[txrx] = NULL;
- }
- }
- tls->cipher_type[txrx] = TLS_CIPHER_STREAM;
- if (tls->mac[txrx]) {
- l_checksum_free(tls->mac[txrx]);
- tls->mac[txrx] = NULL;
- }
- tls->mac_length[txrx] = 0;
- tls->block_length[txrx] = 0;
- tls->record_iv_length[txrx] = 0;
- if (tls->fixed_iv_length[txrx]) {
- explicit_bzero(tls->fixed_iv[txrx], tls->fixed_iv_length[txrx]);
- tls->fixed_iv_length[txrx] = 0;
- }
- tls->auth_tag_length[txrx] = 0;
- tls->seq_num[txrx] = 0;
- tls->cipher_suite[txrx] = tls->pending.cipher_suite;
- if (!tls->cipher_suite[txrx])
- return true;
- key_offset = 0;
- if (tls->cipher_suite[txrx]->mac) {
- mac = tls->cipher_suite[txrx]->mac;
- /* Server write / client read is 2nd in the key block */
- if ((tls->server && txrx) || (!tls->server && !txrx))
- key_offset += mac->mac_length;
- tls->mac[txrx] = l_checksum_new_hmac(mac->hmac_type,
- tls->pending.key_block +
- key_offset, mac->mac_length);
- /* Wipe out the now unneeded part of the key block */
- explicit_bzero(tls->pending.key_block + key_offset,
- mac->mac_length);
- if (!tls->mac[txrx]) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Can't create %s's %s HMAC",
- tls->cipher_suite[txrx]->name,
- txrx ? "Tx" : "Rx");
- }
- return false;
- }
- tls->mac_length[txrx] = mac->mac_length;
- key_offset = 2 * mac->mac_length;
- }
- if (tls->cipher_suite[txrx]->encryption) {
- void *cipher;
- enc = tls->cipher_suite[txrx]->encryption;
- /* Server write / client read is 4th in the key block */
- if ((tls->server && txrx) || (!tls->server && !txrx))
- key_offset += enc->key_length;
- if (enc->cipher_type == TLS_CIPHER_AEAD) {
- cipher = l_aead_cipher_new(enc->l_aead_id,
- tls->pending.key_block +
- key_offset, enc->key_length,
- enc->auth_tag_length);
- tls->aead_cipher[txrx] = cipher;
- } else {
- cipher = l_cipher_new(enc->l_id,
- tls->pending.key_block +
- key_offset, enc->key_length);
- tls->cipher[txrx] = cipher;
- }
- /* Wipe out the now unneeded part of the key block */
- explicit_bzero(tls->pending.key_block + key_offset,
- enc->key_length);
- if (!cipher) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Can't create %s's %s cipher",
- tls->cipher_suite[txrx]->name,
- txrx ? "Tx" : "Rx");
- }
- return false;
- }
- tls->cipher_type[txrx] = enc->cipher_type;
- tls->record_iv_length[txrx] = enc->iv_length -
- enc->fixed_iv_length;
- tls->block_length[txrx] = enc->block_length;
- tls->auth_tag_length[txrx] = enc->auth_tag_length;
- if ((tls->server && txrx) || (!tls->server && !txrx))
- key_offset += enc->key_length;
- else
- key_offset += 2 * enc->key_length;
- }
- if (tls->negotiated_version <= L_TLS_V10 &&
- tls->cipher_suite[txrx]->encryption &&
- tls->cipher_suite[txrx]->encryption->cipher_type ==
- TLS_CIPHER_BLOCK) {
- enc = tls->cipher_suite[txrx]->encryption;
- /* Server write / client read is 6th in the key block */
- if ((tls->server && txrx) || (!tls->server && !txrx))
- key_offset += enc->iv_length;
- l_cipher_set_iv(tls->cipher[txrx], tls->pending.key_block +
- key_offset, enc->iv_length);
- /* Wipe out the now unneeded part of the key block */
- explicit_bzero(tls->pending.key_block + key_offset,
- enc->iv_length);
- } else if (tls->cipher_suite[txrx]->encryption &&
- tls->cipher_suite[txrx]->encryption->fixed_iv_length) {
- enc = tls->cipher_suite[txrx]->encryption;
- /* Server write / client read is 6th in the key block */
- if ((tls->server && txrx) || (!tls->server && !txrx))
- key_offset += enc->fixed_iv_length;
- tls->fixed_iv_length[txrx] = enc->fixed_iv_length;
- memcpy(tls->fixed_iv[txrx], tls->pending.key_block + key_offset,
- enc->fixed_iv_length);
- /* Wipe out the now unneeded part of the key block */
- explicit_bzero(tls->pending.key_block + key_offset,
- enc->fixed_iv_length);
- }
- return true;
- }
- static void tls_reset_cipher_spec(struct l_tls *tls, bool txrx)
- {
- /* Reset everything to the TLS_NULL_WITH_NULL_NULL state */
- tls->pending.cipher_suite = NULL;
- tls_change_cipher_spec(tls, txrx, NULL);
- }
- bool tls_cipher_suite_is_compatible(struct l_tls *tls,
- const struct tls_cipher_suite *suite,
- const char **error)
- {
- static char error_buf[200];
- struct l_cert *leaf;
- enum l_tls_version min_version =
- tls->negotiated_version ?: tls->min_version;
- enum l_tls_version max_version =
- tls->negotiated_version ?: tls->max_version;
- if (suite->encryption &&
- suite->encryption->cipher_type == TLS_CIPHER_AEAD) {
- if (max_version < L_TLS_V12) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s uses an AEAD "
- "cipher (TLS 1.2+) but "
- TLS_VER_FMT
- " was negotiated or is the max "
- "version allowed", suite->name,
- TLS_VER_ARGS(tls->max_version));
- }
- return false;
- }
- if (!l_aead_cipher_is_supported(suite->encryption->l_aead_id)) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s's AEAD cipher "
- "algorithm not supported by "
- "the kernel", suite->name);
- }
- return false;
- }
- } else if (suite->encryption) { /* Block or stream cipher */
- if (!l_cipher_is_supported(suite->encryption->l_id)) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s's block/stream"
- " cipher algorithm not "
- "supported by the kernel",
- suite->name);
- }
- return false;
- }
- }
- if (suite->mac &&
- !l_checksum_is_supported(suite->mac->hmac_type, true)) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s's HMAC algorithm not "
- "supported by the kernel", suite->name);
- }
- return false;
- }
- if (
- (max_version < L_TLS_V12 &&
- (!l_checksum_is_supported(L_CHECKSUM_MD5, true) ||
- !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) ||
- (min_version >= L_TLS_V12 &&
- !l_checksum_is_supported(
- suite->prf_hmac != L_CHECKSUM_NONE ?
- suite->prf_hmac : L_CHECKSUM_SHA256,
- true))) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s's PRF algorithm not "
- "supported by the kernel", suite->name);
- }
- return false;
- }
- if (suite->key_xchg->need_ffdh &&
- !l_key_is_supported(L_KEY_FEATURE_DH)) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Cipher suite %s's key exchange "
- "mechanism needs kernel DH support",
- suite->name);
- }
- return false;
- }
- /*
- * If the certificate is compatible with the signature algorithm it
- * also must be compatible with the key exchange mechanism because
- * the cipher suites are defined so that the same certificates can
- * be used by both.
- */
- leaf = l_certchain_get_leaf(tls->cert);
- if (leaf && suite->signature &&
- !suite->signature->validate_cert_key_type(leaf)) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "Local certificate has key type "
- "incompatible with cipher suite %s's "
- "signature algorithm", suite->name);
- }
- return false;
- }
- /*
- * On the server we know what elliptic curve we'll be using as soon
- * as we've processed the ClientHello so for EC-based key exchange
- * methods require that a curve has been selected.
- */
- if (suite->key_xchg->need_ecc && tls->server &&
- !tls->negotiated_curve) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "No common supported elliptic curves "
- "with the client, can't use %s",
- suite->name);
- }
- return false;
- }
- /* Similarly for FF DH groups */
- if (suite->key_xchg->need_ffdh && tls->server &&
- !tls->negotiated_ff_group) {
- if (error) {
- *error = error_buf;
- snprintf(error_buf, sizeof(error_buf),
- "No common supported finite-field "
- "groups with the client, can't use %s",
- suite->name);
- }
- return false;
- }
- return true;
- }
- static struct tls_cipher_suite *tls_find_cipher_suite(const uint8_t *id)
- {
- struct tls_cipher_suite **suite;
- for (suite = tls_cipher_suite_pref; *suite; suite++)
- if ((*suite)->id[0] == id[0] && (*suite)->id[1] == id[1])
- return *suite;
- return NULL;
- }
- static struct tls_compression_method tls_compression_pref[] = {
- {
- 0,
- "CompressionMethod.null",
- },
- };
- static struct tls_compression_method *tls_find_compression_method(
- const uint8_t id)
- {
- int i;
- for (i = 0; i < (int) L_ARRAY_SIZE(tls_compression_pref); i++)
- if (tls_compression_pref[i].id == id)
- return &tls_compression_pref[i];
- return NULL;
- }
- const struct tls_hash_algorithm tls_handshake_hash_data[] = {
- [HANDSHAKE_HASH_SHA384] = { 5, HANDSHAKE_HASH_SHA384,
- L_CHECKSUM_SHA384, "SHA384" },
- [HANDSHAKE_HASH_SHA256] = { 4, HANDSHAKE_HASH_SHA256,
- L_CHECKSUM_SHA256, "SHA256" },
- [HANDSHAKE_HASH_MD5] = { 1, HANDSHAKE_HASH_MD5,
- L_CHECKSUM_MD5, "MD5" },
- [HANDSHAKE_HASH_SHA1] = { 2, HANDSHAKE_HASH_SHA1,
- L_CHECKSUM_SHA1, "SHA1" },
- };
- static bool tls_init_handshake_hash(struct l_tls *tls)
- {
- enum handshake_hash_type hash;
- bool tls10 = tls->max_version < L_TLS_V12;
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
- /* Skip hash types we already know we won't need */
- if (tls10 && hash != HANDSHAKE_HASH_SHA1 &&
- hash != HANDSHAKE_HASH_MD5)
- continue;
- if (tls->handshake_hash[hash]) {
- TLS_DEBUG("Handshake hash %s already exists",
- tls_handshake_hash_data[hash].name);
- goto err;
- }
- tls->handshake_hash[hash] = l_checksum_new(
- tls_handshake_hash_data[hash].l_id);
- if (!tls->handshake_hash[hash]) {
- TLS_DEBUG("Can't create %s hash",
- tls_handshake_hash_data[hash].name);
- goto err;
- }
- }
- return true;
- err:
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
- tls_drop_handshake_hash(tls, hash);
- return false;
- }
- static const struct tls_hash_algorithm *tls_set_prf_hmac(struct l_tls *tls)
- {
- enum handshake_hash_type hash;
- if (tls->pending.cipher_suite->prf_hmac == L_CHECKSUM_NONE) {
- tls->prf_hmac = &tls_handshake_hash_data[HANDSHAKE_HASH_SHA256];
- return tls->prf_hmac;
- }
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
- if (tls_handshake_hash_data[hash].l_id ==
- tls->pending.cipher_suite->prf_hmac) {
- tls->prf_hmac = &tls_handshake_hash_data[hash];
- return tls->prf_hmac;
- }
- return NULL;
- }
- static bool tls_domain_match_mask(const char *name, size_t name_len,
- const char *mask, size_t mask_len)
- {
- bool at_start = true;
- while (1) {
- const char *name_seg_end = memchr(name, '.', name_len);
- const char *mask_seg_end = memchr(mask, '.', mask_len);
- size_t name_seg_len = name_seg_end ?
- (size_t) (name_seg_end - name) : name_len;
- size_t mask_seg_len = mask_seg_end ?
- (size_t) (mask_seg_end - mask) : mask_len;
- if (mask_seg_len == 1 && mask[0] == '*') {
- /*
- * A * at the beginning of the mask matches any
- * number of labels.
- */
- if (at_start && name_seg_end &&
- tls_domain_match_mask(name_seg_end + 1,
- name_len - name_seg_len - 1,
- mask, mask_len))
- return true;
- goto ok_next;
- }
- if (name_seg_len != mask_seg_len ||
- memcmp(name, mask, name_seg_len))
- return false;
- ok_next:
- /* If either string ends here both must end here */
- if (!name_seg_end || !mask_seg_end)
- return !name_seg_end && !mask_seg_end;
- at_start = false;
- name = name_seg_end + 1;
- name_len -= name_seg_len + 1;
- mask = mask_seg_end + 1;
- mask_len -= mask_seg_len + 1;
- }
- }
- static const struct asn1_oid subject_alt_name_oid =
- { 3, { 0x55, 0x1d, 0x11 } };
- static const struct asn1_oid dn_common_name_oid =
- { 3, { 0x55, 0x04, 0x03 } };
- #define SAN_DNS_NAME_ID ASN1_CONTEXT_IMPLICIT(2)
- static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask,
- char **error_msg)
- {
- const uint8_t *san, *dn, *end;
- size_t san_len, dn_len;
- uint8_t san_tag;
- const char *cn = NULL;
- size_t cn_len;
- char **i;
- struct l_string *dns_names = NULL;
- int dns_name_count = 0;
- /*
- * Locate SubjectAltName (RFC5280 Section 4.2.1.6) and descend into
- * the sole SEQUENCE element, check if any DNSName matches.
- */
- san = cert_get_extension(cert, &subject_alt_name_oid, NULL, &san_len);
- if (san) {
- san = asn1_der_find_elem(san, san_len, 0, &san_tag, &san_len);
- if (unlikely(!san || san_tag != ASN1_ID_SEQUENCE))
- goto parse_error;
- end = san + san_len;
- while (san < end) {
- const uint8_t *value;
- uint8_t tag;
- size_t len;
- value = asn1_der_find_elem(san, end - san,
- SAN_DNS_NAME_ID,
- &tag, &len);
- if (!value)
- break;
- /* Type is implicitly IA5STRING */
- for (i = mask; *i; i++)
- if (tls_domain_match_mask((const char *) value,
- len, *i, strlen(*i))) {
- l_string_free(dns_names);
- return true;
- }
- if (!dns_names) {
- dns_names = l_string_new(128);
- l_string_append(dns_names, "tried DNSName(s) ");
- l_string_append_fixed(dns_names,
- (char *) value, len);
- } else if (dns_name_count < 20) {
- l_string_append(dns_names, ", ");
- l_string_append_fixed(dns_names,
- (char *) value, len);
- }
- san = value + len;
- dns_name_count++;
- }
- }
- /*
- * Retrieve the Common Name from the Subject DN and check if it
- * matches.
- *
- * We look at the Common Name only if no DNSNames were present in
- * the certificate, following Wi-Fi Alliance's Hotspot 2.0
- * Specification v3.1 section 7.3.3.2 step 2:
- * "Verify in the AAA server certificate that the domain name from
- * the FQDN [...] is a suffix match of the domain name in at least
- * one of the DNSName SubjectAltName extensions. If a SubjectAltName
- * of type DNSName is not present, then the domain name from the
- * FQDN shall be a suffix match to the CommonName portion of the
- * SubjectName. If neither of these conditions holds, then
- * verification fails."
- */
- if (dns_name_count) {
- if (dns_name_count > 20)
- l_string_append_printf(dns_names, " and %i other",
- dns_name_count - 20);
- *error_msg = l_string_unwrap(dns_names);
- return false;
- }
- dn = l_cert_get_dn(cert, &dn_len);
- if (unlikely(!dn))
- goto parse_error;
- end = dn + dn_len;
- while (dn < end) {
- const uint8_t *set, *seq, *oid, *name;
- uint8_t tag;
- size_t len, oid_len, name_len;
- set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len);
- if (unlikely(!set || tag != ASN1_ID_SET))
- goto parse_error;
- dn = set + len;
- seq = asn1_der_find_elem(set, len, 0, &tag, &len);
- if (unlikely(!seq || tag != ASN1_ID_SEQUENCE))
- goto parse_error;
- oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len);
- if (unlikely(!oid || tag != ASN1_ID_OID))
- goto parse_error;
- name = asn1_der_find_elem(seq, len, 1, &tag, &name_len);
- if (unlikely(!name || (tag != ASN1_ID_PRINTABLESTRING &&
- tag != ASN1_ID_UTF8STRING &&
- tag != ASN1_ID_IA5STRING)))
- continue;
- if (asn1_oid_eq(&dn_common_name_oid, oid_len, oid)) {
- cn = (const char *) name;
- cn_len = name_len;
- break;
- }
- }
- if (unlikely(!cn))
- goto parse_error;
- for (i = mask; *i; i++)
- if (tls_domain_match_mask(cn, cn_len, *i, strlen(*i)))
- return true;
- *error_msg = l_strdup_printf("tried CommonName %.*s", (int) cn_len, cn);
- return false;
- parse_error:
- *error_msg = l_strdup("couldn't locate DNSName or CommonName");
- return false;
- }
- #define SWITCH_ENUM_TO_STR(val) \
- case (val): \
- return L_STRINGIFY(val);
- static const char *tls_handshake_type_to_str(enum tls_handshake_type type)
- {
- static char buf[100];
- switch (type) {
- SWITCH_ENUM_TO_STR(TLS_HELLO_REQUEST)
- SWITCH_ENUM_TO_STR(TLS_CLIENT_HELLO)
- SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO)
- SWITCH_ENUM_TO_STR(TLS_CERTIFICATE)
- SWITCH_ENUM_TO_STR(TLS_SERVER_KEY_EXCHANGE)
- SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_REQUEST)
- SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO_DONE)
- SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_VERIFY)
- SWITCH_ENUM_TO_STR(TLS_CLIENT_KEY_EXCHANGE)
- SWITCH_ENUM_TO_STR(TLS_FINISHED)
- }
- snprintf(buf, sizeof(buf), "tls_handshake_type(%i)", type);
- return buf;
- }
- static void tls_send_alert(struct l_tls *tls, bool fatal,
- enum l_tls_alert_desc alert_desc)
- {
- uint8_t buf[2];
- TLS_DEBUG("Sending a %s Alert: %s", fatal ? "Fatal" : "Warning",
- l_tls_alert_to_str(alert_desc));
- buf[0] = fatal ? 2 : 1;
- buf[1] = alert_desc;
- tls_tx_record(tls, TLS_CT_ALERT, buf, 2);
- }
- /*
- * Callers make sure this is about the last function before returning
- * from the stack frames up to the exported library call so that the
- * user-supplied disconnected callback here is free to use l_tls_free
- * for example.
- */
- void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc,
- enum l_tls_alert_desc local_desc)
- {
- tls_send_alert(tls, true, desc);
- tls_reset_handshake(tls);
- tls_cleanup_handshake(tls);
- tls_reset_cipher_spec(tls, 0);
- tls_reset_cipher_spec(tls, 1);
- tls->negotiated_version = 0;
- tls->ready = false;
- tls->disconnected(local_desc ?: desc, local_desc && !desc,
- tls->user_data);
- }
- void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf, size_t length)
- {
- int i;
- TLS_DEBUG("Sending a %s of %zi bytes",
- tls_handshake_type_to_str(type),
- length - TLS_HANDSHAKE_HEADER_SIZE);
- /* Fill in the handshake header */
- buf[0] = type;
- buf[1] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 16;
- buf[2] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 8;
- buf[3] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 0;
- for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
- if (tls->handshake_hash[i])
- l_checksum_update(tls->handshake_hash[i], buf, length);
- tls_tx_record(tls, TLS_CT_HANDSHAKE, buf, length);
- }
- static ssize_t tls_append_hello_extensions(struct l_tls *tls,
- struct l_queue *extensions,
- uint8_t *buf, size_t len)
- {
- uint8_t *ptr = buf;
- uint8_t *extensions_len_ptr = ptr;
- bool client_hello = !tls->server;
- unsigned int i = 0;
- const struct l_queue_entry *entry = l_queue_get_entries(extensions);
- if (len < 2)
- return -ENOSPC;
- ptr += 2;
- len -= 2;
- while (1) {
- const struct tls_hello_extension *extension;
- ssize_t ext_len;
- ssize_t (*ext_write)(struct l_tls *tls,
- uint8_t *buf, size_t len);
- if (client_hello) {
- extension = &tls_extensions[i++];
- if (!extension->name)
- break;
- ext_write = extension->client_write;
- } else {
- uint16_t ext_id;
- if (!entry)
- break;
- ext_id = L_PTR_TO_UINT(entry->data);
- entry = entry->next;
- for (i = 0; tls_extensions[i].name; i++)
- if (tls_extensions[i].id == ext_id)
- break;
- extension = &tls_extensions[i];
- if (!extension->name)
- continue;
- ext_write = extension->server_write;
- }
- /*
- * Note: could handle NULL client_write with non-NULL
- * server_handle or server_handle_absent as "server-oriented"
- * extension (7.4.1.4) and write empty extension_data and
- * simliarly require empty extension_data in
- * tls_handle_client_hello if client_handle NULL.
- */
- if (!ext_write)
- continue;
- if (len < 4)
- return -ENOSPC;
- ext_len = ext_write(tls, ptr + 4, len - 4);
- if (ext_len == -ENOMSG)
- continue;
- if (ext_len < 0) {
- TLS_DEBUG("%s extension's %s_write: %s",
- extension->name,
- client_hello ? "client" : "server",
- strerror(-ext_len));
- return ext_len;
- }
- l_put_be16(extension->id, ptr + 0);
- l_put_be16(ext_len, ptr + 2);
- ptr += 4 + ext_len;
- len -= 4 + ext_len;
- }
- if (ptr > extensions_len_ptr + 2)
- l_put_be16(ptr - (extensions_len_ptr + 2), extensions_len_ptr);
- else /* Skip the length if no extensions */
- ptr = extensions_len_ptr;
- return ptr - buf;
- }
- static bool tls_send_client_hello(struct l_tls *tls)
- {
- uint8_t buf[1024 + L_ARRAY_SIZE(tls_compression_pref)];
- uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
- uint8_t *len_ptr;
- unsigned int i;
- ssize_t r;
- struct tls_cipher_suite **suite;
- /* Fill in the Client Hello body */
- *ptr++ = (uint8_t) (tls->max_version >> 8);
- *ptr++ = (uint8_t) (tls->max_version >> 0);
- tls_write_random(tls->pending.client_random);
- memcpy(ptr, tls->pending.client_random, 32);
- ptr += 32;
- *ptr++ = 0; /* No SessionID */
- len_ptr = ptr;
- ptr += 2;
- for (suite = tls->cipher_suite_pref_list; *suite; suite++) {
- const char *error;
- if (!tls_cipher_suite_is_compatible(tls, *suite, &error)) {
- TLS_DEBUG("non-fatal: %s", error);
- continue;
- }
- *ptr++ = (*suite)->id[0];
- *ptr++ = (*suite)->id[1];
- }
- if (ptr == len_ptr + 2) {
- TLS_DEBUG("No compatible cipher suites, check kernel config, "
- "certificate's key type and TLS version range");
- return false;
- }
- l_put_be16((ptr - len_ptr - 2), len_ptr);
- *ptr++ = L_ARRAY_SIZE(tls_compression_pref);
- for (i = 0; i < L_ARRAY_SIZE(tls_compression_pref); i++)
- *ptr++ = tls_compression_pref[i].id;
- r = tls_append_hello_extensions(tls, NULL,
- ptr, buf + sizeof(buf) - ptr);
- if (r < 0)
- return false;
- ptr += r;
- tls_tx_handshake(tls, TLS_CLIENT_HELLO, buf, ptr - buf);
- return true;
- }
- static bool tls_send_server_hello(struct l_tls *tls, struct l_queue *extensions)
- {
- uint8_t buf[1024];
- uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
- ssize_t r;
- /* Fill in the Server Hello body */
- *ptr++ = tls->negotiated_version >> 8;
- *ptr++ = tls->negotiated_version >> 0;
- tls_write_random(tls->pending.server_random);
- memcpy(ptr, tls->pending.server_random, 32);
- ptr += 32;
- *ptr++ = 0; /* Sessions are not cached */
- *ptr++ = tls->pending.cipher_suite->id[0];
- *ptr++ = tls->pending.cipher_suite->id[1];
- *ptr++ = tls->pending.compression_method->id;
- r = tls_append_hello_extensions(tls, extensions,
- ptr, buf + sizeof(buf) - ptr);
- if (r < 0) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "Error appending extensions: %s",
- strerror(-r));
- return false;
- }
- ptr += r;
- tls_tx_handshake(tls, TLS_SERVER_HELLO, buf, ptr - buf);
- return true;
- }
- static bool tls_cert_list_add_size(struct l_cert *cert, void *user_data)
- {
- size_t *total = user_data;
- size_t der_len;
- l_cert_get_der_data(cert, &der_len);
- *total += 3 + der_len;
- return false;
- }
- static bool tls_cert_list_append(struct l_cert *cert, void *user_data)
- {
- uint8_t **ptr = user_data;
- const uint8_t *der;
- size_t der_len;
- der = l_cert_get_der_data(cert, &der_len);
- *(*ptr)++ = der_len >> 16;
- *(*ptr)++ = der_len >> 8;
- *(*ptr)++ = der_len >> 0;
- memcpy(*ptr, der, der_len);
- *ptr += der_len;
- return false;
- }
- static bool tls_send_certificate(struct l_tls *tls)
- {
- uint8_t *buf, *ptr;
- size_t total;
- if (tls->server && !tls->cert) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT,
- "Certificate needed in server mode");
- return false;
- }
- /*
- * TODO: check that the certificate is compatible with hash and
- * signature algorithms lists supplied to us in the Client Hello
- * extensions (if we're a 1.2+ server) or in the Certificate Request
- * (if we act as a 1.2+ client).
- *
- * - for the hash and signature_algorithms list, check all
- * certs in the cert chain.
- *
- * - also if !cipher_suite->key_xchg->key_exchange_msg, check that the
- * end entity certificate's key type matches and is usable with some
- * hash/signature pair.
- *
- * - on client check if any of the supplied DNs (if any) match
- * anything in our cert chain.
- */
- total = 0;
- l_certchain_walk_from_leaf(tls->cert, tls_cert_list_add_size, &total);
- buf = l_malloc(128 + total);
- ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
- /* Fill in the Certificate body */
- *ptr++ = total >> 16;
- *ptr++ = total >> 8;
- *ptr++ = total >> 0;
- l_certchain_walk_from_leaf(tls->cert, tls_cert_list_append, &ptr);
- tls_tx_handshake(tls, TLS_CERTIFICATE, buf, ptr - buf);
- l_free(buf);
- if (tls->cert)
- tls->cert_sent = true;
- return true;
- }
- /*
- * Note: ClientCertificateType.rsa_sign value coincides with the
- * SignatureAlgorithm.rsa value but other values in those enum are
- * different so we don't mix them, can't extract them from
- * tls->pending.cipher_suite->signature.
- */
- static uint8_t tls_cert_type_pref[] = {
- 1, /* RSA_sign */
- };
- static bool tls_send_certificate_request(struct l_tls *tls)
- {
- uint8_t *buf, *ptr, *dn_ptr;
- size_t len;
- const struct l_queue_entry *entry;
- unsigned int i;
- size_t dn_total = 0;
- for (entry = l_queue_get_entries(tls->ca_certs); entry;
- entry = entry->next) {
- struct l_cert *ca_cert = entry->data;
- size_t dn_size;
- if (l_cert_get_dn(ca_cert, &dn_size))
- dn_total += 10 + dn_size;
- }
- len = 256 + L_ARRAY_SIZE(tls_cert_type_pref) + dn_total;
- buf = l_malloc(len);
- ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
- /* Fill in the Certificate Request body */
- *ptr++ = L_ARRAY_SIZE(tls_cert_type_pref);
- for (i = 0; i < L_ARRAY_SIZE(tls_cert_type_pref); i++)
- *ptr++ = tls_cert_type_pref[i];
- if (tls->negotiated_version >= L_TLS_V12) {
- ssize_t ret = tls_write_signature_algorithms(tls, ptr,
- buf + len - ptr);
- if (ret < 0) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "tls_write_signature_algorithms: %s",
- strerror(-ret));
- l_free(buf);
- return false;
- }
- ptr += ret;
- }
- dn_ptr = ptr;
- ptr += 2; /* Leave space for the total DN size */
- for (entry = l_queue_get_entries(tls->ca_certs); entry;
- entry = entry->next) {
- struct l_cert *ca_cert = entry->data;
- size_t dn_size;
- const uint8_t *dn = l_cert_get_dn(ca_cert, &dn_size);
- uint8_t *cur_dn_ptr = ptr;
- if (!dn)
- continue;
- ptr += 2; /* Leave space for current DN size */
- *ptr++ = ASN1_ID_SEQUENCE; /* DER outer SEQUENCE tag */
- asn1_write_definite_length(&ptr, dn_size); /* length */
- memcpy(ptr, dn, dn_size); /* value */
- ptr += dn_size;
- l_put_be16(ptr - cur_dn_ptr - 2, cur_dn_ptr);
- }
- l_put_be16(ptr - dn_ptr - 2, dn_ptr); /* DistinguishedNames size */
- tls_tx_handshake(tls, TLS_CERTIFICATE_REQUEST, buf, ptr - buf);
- l_free(buf);
- return true;
- }
- static void tls_send_server_hello_done(struct l_tls *tls)
- {
- uint8_t buf[32];
- /* No body */
- tls_tx_handshake(tls, TLS_SERVER_HELLO_DONE, buf,
- TLS_HANDSHAKE_HEADER_SIZE);
- }
- void tls_generate_master_secret(struct l_tls *tls,
- const uint8_t *pre_master_secret,
- int pre_master_secret_len)
- {
- uint8_t seed[64];
- int key_block_size;
- memcpy(seed + 0, tls->pending.client_random, 32);
- memcpy(seed + 32, tls->pending.server_random, 32);
- tls_prf_get_bytes(tls, pre_master_secret, pre_master_secret_len,
- "master secret", seed, 64,
- tls->pending.master_secret, 48);
- /* Directly generate the key block while we're at it */
- key_block_size = 0;
- if (tls->pending.cipher_suite->encryption)
- key_block_size += 2 *
- tls->pending.cipher_suite->encryption->key_length;
- if (tls->pending.cipher_suite->mac)
- key_block_size += 2 *
- tls->pending.cipher_suite->mac->mac_length;
- if (tls->pending.cipher_suite->encryption &&
- tls->negotiated_version <= L_TLS_V10 &&
- tls->pending.cipher_suite->encryption->cipher_type ==
- TLS_CIPHER_BLOCK)
- key_block_size += 2 *
- tls->pending.cipher_suite->encryption->iv_length;
- if (tls->pending.cipher_suite->encryption)
- key_block_size += 2 * tls->pending.cipher_suite->encryption->
- fixed_iv_length;
- /* Reverse order from the master secret seed */
- memcpy(seed + 0, tls->pending.server_random, 32);
- memcpy(seed + 32, tls->pending.client_random, 32);
- tls_prf_get_bytes(tls, tls->pending.master_secret, 48,
- "key expansion", seed, 64,
- tls->pending.key_block, key_block_size);
- explicit_bzero(seed, 64);
- }
- static void tls_get_handshake_hash(struct l_tls *tls,
- enum handshake_hash_type type,
- uint8_t *out)
- {
- struct l_checksum *hash = l_checksum_clone(tls->handshake_hash[type]);
- if (!hash)
- return;
- l_checksum_get_digest(hash, out, l_checksum_digest_length(
- tls_handshake_hash_data[type].l_id));
- l_checksum_free(hash);
- }
- static bool tls_get_handshake_hash_by_type(struct l_tls *tls,
- enum handshake_hash_type type,
- const uint8_t *data, size_t data_len,
- uint8_t *out, size_t *out_len)
- {
- if (!tls->handshake_hash[type])
- return false;
- if (out_len)
- *out_len = l_checksum_digest_length(
- tls_handshake_hash_data[type].l_id);
- tls_get_handshake_hash(tls, type, out);
- return true;
- }
- static bool tls_send_certificate_verify(struct l_tls *tls)
- {
- uint8_t buf[2048];
- int i;
- ssize_t sign_len;
- /* Fill in the Certificate Verify body */
- sign_len = tls->pending.cipher_suite->signature->sign(tls,
- buf + TLS_HANDSHAKE_HEADER_SIZE,
- 2048 - TLS_HANDSHAKE_HEADER_SIZE,
- tls_get_handshake_hash_by_type,
- NULL, 0);
- if (sign_len < 0)
- return false;
- /* Stop maintaining handshake message hashes other than the PRF hash */
- if (tls->negotiated_version >= L_TLS_V12)
- for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
- if (&tls_handshake_hash_data[i] != tls->prf_hmac)
- tls_drop_handshake_hash(tls, i);
- tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf,
- sign_len + TLS_HANDSHAKE_HEADER_SIZE);
- return true;
- }
- static void tls_send_change_cipher_spec(struct l_tls *tls)
- {
- uint8_t buf = 1;
- tls_tx_record(tls, TLS_CT_CHANGE_CIPHER_SPEC, &buf, 1);
- }
- static void tls_send_finished(struct l_tls *tls)
- {
- uint8_t buf[512];
- uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
- uint8_t seed[HANDSHAKE_HASH_MAX_SIZE * 2];
- size_t seed_len;
- if (tls->negotiated_version >= L_TLS_V12) {
- /* Same hash type as that used for the PRF (usually SHA256) */
- tls_get_handshake_hash(tls, tls->prf_hmac->type, seed);
- seed_len = l_checksum_digest_length(tls->prf_hmac->l_id);
- } else {
- tls_get_handshake_hash(tls, HANDSHAKE_HASH_MD5, seed + 0);
- tls_get_handshake_hash(tls, HANDSHAKE_HASH_SHA1, seed + 16);
- seed_len = 36;
- }
- tls_prf_get_bytes(tls, tls->pending.master_secret, 48,
- tls->server ? "server finished" :
- "client finished",
- seed, seed_len,
- ptr, tls->cipher_suite[1]->verify_data_length);
- ptr += tls->cipher_suite[1]->verify_data_length;
- tls_tx_handshake(tls, TLS_FINISHED, buf, ptr - buf);
- }
- static bool tls_verify_finished(struct l_tls *tls, const uint8_t *received,
- size_t len)
- {
- uint8_t expected[tls->cipher_suite[0]->verify_data_length];
- uint8_t *seed;
- size_t seed_len;
- if (len != (size_t) tls->cipher_suite[0]->verify_data_length) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "TLS_FINISHED length not %i",
- tls->cipher_suite[0]->verify_data_length);
- return false;
- }
- if (tls->negotiated_version >= L_TLS_V12) {
- enum handshake_hash_type hash = tls->prf_hmac->type;
- seed = tls->prev_digest[hash];
- seed_len = l_checksum_digest_length(tls->prf_hmac->l_id);
- } else {
- seed = alloca(36);
- memcpy(seed + 0, tls->prev_digest[HANDSHAKE_HASH_MD5], 16);
- memcpy(seed + 16, tls->prev_digest[HANDSHAKE_HASH_SHA1], 20);
- seed_len = 36;
- }
- tls_prf_get_bytes(tls, tls->pending.master_secret, 48,
- tls->server ? "client finished" :
- "server finished",
- seed, seed_len,
- expected,
- tls->cipher_suite[0]->verify_data_length);
- if (memcmp(received, expected, len)) {
- TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0,
- "TLS_FINISHED contents don't match");
- return false;
- }
- return true;
- }
- static bool tls_ptr_match(const void *a, const void *b)
- {
- return a == b;
- }
- static bool tls_handle_hello_extensions(struct l_tls *tls,
- const uint8_t *buf, size_t len,
- struct l_queue *seen)
- {
- unsigned int i;
- const struct tls_hello_extension *extension;
- bool client_hello = tls->server;
- uint16_t extensions_size;
- if (!len)
- return true;
- if (len < 2 || len > 2 + 65535)
- goto decode_error;
- extensions_size = l_get_be16(buf);
- len -= 2;
- buf += 2;
- if (len != extensions_size)
- goto decode_error;
- while (len) {
- uint16_t ext_id;
- size_t ext_len;
- bool (*handler)(struct l_tls *tls,
- const uint8_t *buf, size_t len);
- if (len < 4)
- goto decode_error;
- ext_id = l_get_be16(buf + 0);
- ext_len = l_get_be16(buf + 2);
- buf += 4;
- len -= 4;
- if (ext_len > len)
- goto decode_error;
- /*
- * RFC 5246, Section 7.4.1.4: "There MUST NOT be more than
- * one extension of the same type."
- */
- if (l_queue_find(seen, tls_ptr_match, L_UINT_TO_PTR(ext_id))) {
- TLS_DEBUG("Duplicate extension %u", ext_id);
- goto decode_error;
- }
- l_queue_push_tail(seen, L_UINT_TO_PTR(ext_id));
- extension = NULL;
- for (i = 0; tls_extensions[i].name; i++)
- if (tls_extensions[i].id == ext_id) {
- extension = &tls_extensions[i];
- break;
- }
- if (!extension)
- goto next;
- handler = client_hello ?
- extension->client_handle : extension->server_handle;
- /*
- * RFC 5246, Section 7.4.1.4: "If a client receives an
- * extension type in ServerHello that it did not request in
- * the associated ClientHello, it MUST abort the handshake
- * with an unsupported_extension fatal alert."
- * There are however servers that include an unsolicited
- * Supported Point Format extension where the handshake
- * still completes fine if the extension is ignored so we
- * do this instead.
- */
- if (!client_hello && !handler) {
- TLS_DEBUG("non-fatal: %s extension not expected in "
- "a ServerHello", extension->name);
- goto next;
- }
- if (!handler(tls, buf, ext_len)) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "Hello %s extension parse error",
- extension->name);
- return false;
- }
- next:
- buf += ext_len;
- len -= ext_len;
- }
- /*
- * Trigger any actions needed when an extension is missing and its
- * handler has not been called yet.
- */
- for (i = 0; tls_extensions[i].name; i++) {
- bool (*handler)(struct l_tls *tls);
- extension = &tls_extensions[i];
- handler = client_hello ?
- extension->client_handle_absent :
- extension->server_handle_absent;
- if (!handler)
- continue;
- if (l_queue_find(seen, tls_ptr_match,
- L_UINT_TO_PTR(extension->id)))
- continue;
- if (!handler(tls)) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "Hello %s extension missing",
- extension->name);
- return false;
- }
- }
- return true;
- decode_error:
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "Hello extensions decode error");
- return false;
- }
- static void tls_handle_client_hello(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- uint16_t cipher_suites_size;
- uint8_t session_id_size, compression_methods_size;
- const uint8_t *cipher_suites;
- const uint8_t *compression_methods;
- int i;
- struct l_queue *extensions_offered = NULL;
- enum l_tls_alert_desc alert_desc = TLS_ALERT_HANDSHAKE_FAIL;
- /* Do we have enough for ProtocolVersion + Random + SessionID size? */
- if (len < 2 + 32 + 1)
- goto decode_error;
- memcpy(tls->pending.client_random, buf + 2, 32);
- session_id_size = buf[34];
- len -= 35;
- /*
- * Do we have enough to hold the actual session ID + 2 byte field for
- * cipher_suite len + minimum of a single cipher suite identifier
- */
- if (len < (size_t) session_id_size + 4)
- goto decode_error;
- len -= session_id_size + 2;
- cipher_suites_size = l_get_be16(buf + 35 + session_id_size);
- cipher_suites = buf + 37 + session_id_size;
- /*
- * Check that size is not odd, more than 0 and we have enough
- * data in the packet for cipher_suites_size + 2 bytes for
- * compression_methods_size + a single compression method
- */
- if (len < (size_t) cipher_suites_size + 2 ||
- (cipher_suites_size & 1) || cipher_suites_size == 0)
- goto decode_error;
- len -= cipher_suites_size + 1;
- compression_methods_size = cipher_suites[cipher_suites_size];
- compression_methods = cipher_suites + cipher_suites_size + 1;
- if (len < (size_t) compression_methods_size ||
- compression_methods_size == 0)
- goto decode_error;
- len -= compression_methods_size;
- extensions_offered = l_queue_new();
- if (!tls_handle_hello_extensions(tls, compression_methods +
- compression_methods_size,
- len, extensions_offered))
- goto cleanup;
- /*
- * Note: if the client is supplying a SessionID we know it is false
- * because our server implementation never generates any SessionIDs
- * yet so either the client is attempting something strange or was
- * trying to connect somewhere else. We might want to throw an error.
- */
- /* Save client_version for Premaster Secret verification */
- tls->client_version = l_get_be16(buf);
- if (tls->client_version < tls->min_version) {
- TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0,
- "Client version too low: %02x",
- tls->client_version);
- goto cleanup;
- }
- tls->negotiated_version = tls->client_version > tls->max_version ?
- tls->max_version : tls->client_version;
- /* Stop maintaining handshake message hashes other than MD1 and SHA. */
- if (tls->negotiated_version < L_TLS_V12)
- for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
- if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
- tls_drop_handshake_hash(tls, i);
- TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
- TLS_VER_ARGS(tls->negotiated_version));
- if (!tls->cipher_suite_pref_list) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "No usable cipher suites");
- goto cleanup;
- }
- /* Select a cipher suite according to client's preference list */
- while (cipher_suites_size) {
- struct tls_cipher_suite *suite =
- tls_find_cipher_suite(cipher_suites);
- struct tls_cipher_suite **iter;
- const char *error;
- for (iter = tls->cipher_suite_pref_list; *iter; iter++)
- if (*iter == suite)
- break;
- if (!suite)
- TLS_DEBUG("non-fatal: Cipher suite %04x unknown",
- l_get_be16(cipher_suites));
- else if (!tls_cipher_suite_is_compatible(tls, suite, &error))
- TLS_DEBUG("non-fatal: %s", error);
- else if (!*iter) {
- /*
- * We have at least one matching compatible suite but
- * it is not allowed in this security profile. If the
- * handshake ends up failing then we blame the security
- * profile.
- */
- alert_desc = TLS_ALERT_INSUFFICIENT_SECURITY;
- TLS_DEBUG("non-fatal: Cipher suite %s disallowed "
- "by config", suite->name);
- } else {
- tls->pending.cipher_suite = suite;
- break;
- }
- cipher_suites += 2;
- cipher_suites_size -= 2;
- }
- if (!cipher_suites_size) {
- TLS_DISCONNECT(alert_desc, 0,
- "No common cipher suites matching negotiated "
- "TLS version and our certificate's key type");
- goto cleanup;
- }
- if (!tls_set_prf_hmac(tls)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "Error selecting the PRF HMAC");
- goto cleanup;
- }
- TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name);
- /* Select a compression method */
- /* CompressionMethod.null must be present in the vector */
- while (compression_methods_size) {
- tls->pending.compression_method =
- tls_find_compression_method(*compression_methods);
- if (tls->pending.compression_method)
- break;
- compression_methods++;
- compression_methods_size--;
- }
- if (!compression_methods_size) {
- TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
- "No common compression methods");
- goto cleanup;
- }
- TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name);
- if (!tls_send_server_hello(tls, extensions_offered))
- goto cleanup;
- l_queue_destroy(extensions_offered, NULL);
- if (tls->pending.cipher_suite->signature && tls->cert)
- if (!tls_send_certificate(tls))
- return;
- if (tls->pending.cipher_suite->key_xchg->send_server_key_exchange)
- if (!tls->pending.cipher_suite->key_xchg->
- send_server_key_exchange(tls))
- return;
- /* TODO: don't bother if configured to not authenticate client */
- if (tls->pending.cipher_suite->signature && tls->ca_certs)
- if (!tls_send_certificate_request(tls))
- return;
- tls_send_server_hello_done(tls);
- if (tls->pending.cipher_suite->signature && tls->ca_certs)
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE);
- else
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE);
- return;
- decode_error:
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "ClientHello decode error");
- cleanup:
- l_queue_destroy(extensions_offered, NULL);
- }
- static void tls_handle_server_hello(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- uint8_t session_id_size, cipher_suite_id[2], compression_method_id;
- const char *error;
- struct tls_cipher_suite **iter;
- int i;
- struct l_queue *extensions_seen;
- bool result;
- /* Do we have enough for ProtocolVersion + Random + SessionID len ? */
- if (len < 2 + 32 + 1)
- goto decode_error;
- memcpy(tls->pending.server_random, buf + 2, 32);
- session_id_size = buf[34];
- len -= 35;
- /* Do we have enough for SessionID + CipherSuite ID + Compression ID */
- if (len < (size_t) session_id_size + 2 + 1)
- goto decode_error;
- cipher_suite_id[0] = buf[35 + session_id_size + 0];
- cipher_suite_id[1] = buf[35 + session_id_size + 1];
- compression_method_id = buf[35 + session_id_size + 2];
- len -= session_id_size + 2 + 1;
- extensions_seen = l_queue_new();
- result = tls_handle_hello_extensions(tls, buf + 38 + session_id_size,
- len, extensions_seen);
- l_queue_destroy(extensions_seen, NULL);
- if (!result)
- return;
- tls->negotiated_version = l_get_be16(buf);
- if (tls->negotiated_version < tls->min_version ||
- tls->negotiated_version > tls->max_version) {
- TLS_DISCONNECT(tls->negotiated_version < tls->min_version ?
- TLS_ALERT_PROTOCOL_VERSION :
- TLS_ALERT_ILLEGAL_PARAM, 0,
- "Unsupported version %02x",
- tls->negotiated_version);
- return;
- }
- /* Stop maintaining handshake message hashes other than MD1 and SHA. */
- if (tls->negotiated_version < L_TLS_V12)
- for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
- if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5)
- tls_drop_handshake_hash(tls, i);
- TLS_DEBUG("Negotiated TLS " TLS_VER_FMT,
- TLS_VER_ARGS(tls->negotiated_version));
- /* Set the new cipher suite and compression method structs */
- tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id);
- if (!tls->pending.cipher_suite) {
- TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
- "Unknown cipher suite %04x",
- l_get_be16(cipher_suite_id));
- return;
- }
- for (iter = tls->cipher_suite_pref_list; *iter; iter++)
- if (*iter == tls->pending.cipher_suite)
- break;
- if (!*iter) {
- TLS_DISCONNECT(TLS_ALERT_INSUFFICIENT_SECURITY, 0,
- "Selected cipher suite %s disallowed by config",
- tls->pending.cipher_suite->name);
- return;
- }
- if (!tls_cipher_suite_is_compatible(tls, tls->pending.cipher_suite,
- &error)) {
- TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
- "Selected cipher suite not compatible: %s",
- error);
- return;
- }
- if (!tls_set_prf_hmac(tls)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "Error selecting the PRF HMAC");
- return;
- }
- TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name);
- tls->pending.compression_method =
- tls_find_compression_method(compression_method_id);
- if (!tls->pending.compression_method) {
- TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
- "Unknown compression method %i",
- compression_method_id);
- return;
- }
- TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name);
- if (tls->pending.cipher_suite->signature)
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE);
- else
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE);
- return;
- decode_error:
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "ServerHello decode error");
- }
- static void tls_handle_certificate(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- size_t total;
- _auto_(l_certchain_free) struct l_certchain *certchain = NULL;
- struct l_cert *leaf;
- size_t der_len;
- const uint8_t *der;
- bool dummy;
- const char *error_str;
- char *subject_str;
- if (len < 3)
- goto decode_error;
- /* Length checks */
- total = *buf++ << 16;
- total |= *buf++ << 8;
- total |= *buf++ << 0;
- if (total + 3 != len)
- goto decode_error;
- if (tls_parse_certificate_list(buf, total, &certchain) < 0) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "Error decoding peer certificate chain");
- return;
- }
- /*
- * "Note that a client MAY send no certificates if it does not have any
- * appropriate certificate to send in response to the server's
- * authentication request." -- for now we unconditionally accept
- * an empty certificate chain from the client. Later on we need to
- * make this configurable, if we don't want to authenticate the
- * client then also don't bother sending a Certificate Request.
- */
- if (!certchain) {
- if (!tls->server) {
- TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0,
- "Server sent no certificate chain");
- return;
- }
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE);
- return;
- }
- if (tls->cert_dump_path) {
- int r = pem_write_certificate_chain(certchain,
- tls->cert_dump_path);
- if (r < 0)
- TLS_DEBUG("Error %i (%s) writing the peer certchain "
- "to %s",
- -r, strerror(-r), tls->cert_dump_path);
- else
- TLS_DEBUG("Peer certchain written to %s",
- tls->cert_dump_path);
- }
- /*
- * Validate the certificate chain's consistency and validate it
- * against our CAs if we have any.
- */
- if (!l_certchain_verify(certchain, tls->ca_certs, &error_str)) {
- if (tls->ca_certs) {
- TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0,
- "Peer certchain verification failed "
- "consistency check%s: %s",
- tls->ca_certs ?
- " or against local CA certs" : "",
- error_str);
- return;
- }
- /*
- * Until the mainstream kernel can handle the occasionally
- * used certificates without the AKID extension (both root,
- * which is legal, and non-root, which is iffy but still
- * happens) don't fail on peer certificate chain verification
- * failure when CA certificates were not provided. Knowing
- * that the chain is self-consistent alone doesn't
- * authenticate the peer in any way. Only warn when it looks
- * like the chain is bad but parses and we can get the peer
- * public key from it below.
- */
- TLS_DEBUG("Peer certchain verification failed (%s.) No local "
- "CA certs provided so proceeding anyway. This "
- "failure can signal a security issue or a "
- "known kernel problem with some certificates.",
- error_str);
- }
- /*
- * RFC5246 7.4.2:
- * "The end entity certificate's public key (and associated
- * restrictions) MUST be compatible with the selected key exchange
- * algorithm."
- */
- leaf = l_certchain_get_leaf(certchain);
- if (!tls->pending.cipher_suite->signature->
- validate_cert_key_type(leaf)) {
- TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0,
- "Peer certificate key type incompatible with "
- "pending cipher suite %s",
- tls->pending.cipher_suite->name);
- return;
- }
- if (tls->subject_mask && !tls_cert_domains_match_mask(leaf,
- tls->subject_mask,
- &subject_str)) {
- char *mask = l_strjoinv(tls->subject_mask, '|');
- TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0,
- "Peer certificate's subject domain "
- "doesn't match mask %s: %s", mask, subject_str);
- l_free(mask);
- l_free(subject_str);
- return;
- }
- /* Save the end-entity certificate and free the chain */
- der = l_cert_get_der_data(leaf, &der_len);
- tls->peer_cert = l_cert_new_from_der(der, der_len);
- tls->peer_pubkey = l_cert_get_pubkey(tls->peer_cert);
- if (!tls->peer_pubkey) {
- TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0,
- "Error loading peer public key to kernel");
- return;
- }
- if (!l_key_get_info(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5,
- L_CHECKSUM_NONE, &tls->peer_pubkey_size,
- &dummy)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "Can't l_key_get_info for peer public key");
- return;
- }
- tls->peer_pubkey_size /= 8;
- if (tls->server || tls->pending.cipher_suite->key_xchg->
- handle_server_key_exchange)
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE);
- else
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE);
- return;
- decode_error:
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "TLS_CERTIFICATE decode error");
- }
- static void tls_handle_certificate_request(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- unsigned int cert_type_len, dn_len, i;
- tls->cert_requested = 1;
- cert_type_len = *buf++;
- if (len < 1 + cert_type_len + 2)
- goto decode_error;
- for (i = 0; i < sizeof(tls_cert_type_pref); i++)
- if (memchr(buf, tls_cert_type_pref[i], cert_type_len))
- break;
- if (i == sizeof(tls_cert_type_pref)) {
- TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0,
- "Requested certificate types not supported");
- return;
- }
- buf += cert_type_len;
- len -= 1 + cert_type_len;
- /*
- * TODO: parse and save certificate_types,
- * supported_signature_algorithms and certificate_authorities
- * lists for use in tls_send_certificate.
- */
- if (tls->negotiated_version >= L_TLS_V12) {
- enum handshake_hash_type hash;
- ssize_t ret = tls_parse_signature_algorithms(tls, buf, len);
- if (ret == -ENOTSUP) {
- TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0,
- "No supported signature hash type");
- return;
- }
- if (ret < 0)
- goto decode_error;
- len -= ret;
- buf += ret;
- /*
- * We can now safely stop maintaining handshake message
- * hashes other than the PRF hash and the one selected for
- * signing.
- */
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
- if (&tls_handshake_hash_data[hash] != tls->prf_hmac &&
- hash != tls->signature_hash)
- tls_drop_handshake_hash(tls, hash);
- }
- dn_len = l_get_be16(buf);
- if (2 + dn_len != len)
- goto decode_error;
- return;
- decode_error:
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "CertificateRequest decode error");
- }
- static void tls_handle_server_hello_done(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- const char *error;
- if (len) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "ServerHello not empty");
- return;
- }
- if (tls->cert_requested)
- if (!tls_send_certificate(tls))
- return;
- if (!tls->pending.cipher_suite->key_xchg->send_client_key_exchange(tls))
- return;
- if (tls->cert_sent)
- if (!tls_send_certificate_verify(tls))
- return;
- tls_send_change_cipher_spec(tls);
- if (!tls_change_cipher_spec(tls, 1, &error)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "change_cipher_spec: %s", error);
- return;
- }
- tls_send_finished(tls);
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC);
- }
- static bool tls_get_prev_digest_by_type(struct l_tls *tls,
- enum handshake_hash_type type,
- const uint8_t *data, size_t data_len,
- uint8_t *out, size_t *out_len)
- {
- size_t len;
- if (!tls->handshake_hash[type])
- return false;
- len = l_checksum_digest_length(tls_handshake_hash_data[type].l_id);
- memcpy(out, tls->prev_digest[type], len);
- if (out_len)
- *out_len = len;
- return 0;
- }
- static void tls_handle_certificate_verify(struct l_tls *tls,
- const uint8_t *buf, size_t len)
- {
- int i;
- if (!tls->pending.cipher_suite->signature->verify(tls, buf, len,
- tls_get_prev_digest_by_type,
- NULL, 0))
- return;
- /* Stop maintaining handshake message hashes other than the PRF hash */
- if (tls->negotiated_version >= L_TLS_V12)
- for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++)
- if (&tls_handshake_hash_data[i] != tls->prf_hmac)
- tls_drop_handshake_hash(tls, i);
- /*
- * The client's certificate is now verified based on the following
- * logic:
- * - If we received an (expected) Certificate Verify, we must have
- * sent a Certificate Request.
- * - If we sent a Certificate Request that's because
- * tls->ca_certs is non-NULL.
- * - If tls->ca_certs is non-NULL then tls_handle_certificate
- * will have checked the whole certificate chain to be valid and
- * additionally trusted by our CAs if known.
- * - Additionally cipher_suite->signature->verify has just confirmed
- * that the peer owns the end-entity certificate because it was
- * able to sign the contents of the handshake messages and that
- * signature could be verified with the public key from that
- * certificate.
- */
- tls->peer_authenticated = true;
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC);
- }
- struct dn_element_info {
- const char *str;
- const struct asn1_oid oid;
- };
- static const struct dn_element_info dn_elements[] = {
- { "CN", { 3, { 0x55, 0x04, 0x03 } } },
- { "SN", { 3, { 0x55, 0x04, 0x04 } } },
- { "serialNumber", { 3, { 0x55, 0x04, 0x05 } } },
- { "C", { 3, { 0x55, 0x04, 0x06 } } },
- { "ST", { 3, { 0x55, 0x04, 0x07 } } },
- { "L", { 3, { 0x55, 0x04, 0x08 } } },
- { "street", { 3, { 0x55, 0x04, 0x09 } } },
- { "O", { 3, { 0x55, 0x04, 0x0a } } },
- { "OU", { 3, { 0x55, 0x04, 0x0b } } },
- { "title", { 3, { 0x55, 0x04, 0x0c } } },
- { "telephoneNumber", { 3, { 0x55, 0x04, 0x14 } } },
- { "givenName", { 3, { 0x55, 0x04, 0x2a } } },
- { "initials", { 3, { 0x55, 0x04, 0x2b } } },
- { "emailAddress", {
- 9,
- { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 }
- } },
- { "domainComponent", {
- 10,
- { 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19 }
- } },
- {}
- };
- static void tls_str_escape_append(struct l_string *out, char *str, size_t len)
- {
- while (len--) {
- switch (*str) {
- case '\\':
- case '/':
- case '=':
- l_string_append_c(out, '\\');
- l_string_append_c(out, *str);
- break;
- default:
- l_string_append_c(out, *str);
- break;
- }
- str++;
- }
- }
- static char *tls_get_peer_identity_str(struct l_cert *cert)
- {
- const uint8_t *dn, *end;
- size_t dn_size;
- struct l_string *id_str;
- if (!cert)
- return NULL;
- dn = l_cert_get_dn(cert, &dn_size);
- if (!dn)
- return NULL;
- id_str = l_string_new(200);
- end = dn + dn_size;
- while (dn < end) {
- const uint8_t *set, *seq, *oid, *name;
- uint8_t tag;
- size_t len, oid_len, name_len;
- const struct dn_element_info *info;
- set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len);
- if (!set || tag != ASN1_ID_SET)
- goto error;
- dn = set + len;
- seq = asn1_der_find_elem(set, len, 0, &tag, &len);
- if (!seq || tag != ASN1_ID_SEQUENCE)
- goto error;
- oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len);
- if (!oid || tag != ASN1_ID_OID)
- goto error;
- name = asn1_der_find_elem(seq, len, 1, &tag, &name_len);
- if (!name || (tag != ASN1_ID_PRINTABLESTRING &&
- tag != ASN1_ID_UTF8STRING &&
- tag != ASN1_ID_IA5STRING))
- continue;
- for (info = dn_elements; info->str; info++)
- if (asn1_oid_eq(&info->oid, oid_len, oid))
- break;
- if (!info->str)
- continue;
- l_string_append_c(id_str, '/');
- l_string_append(id_str, info->str);
- l_string_append_c(id_str, '=');
- tls_str_escape_append(id_str, (char *) name, name_len);
- }
- return l_string_unwrap(id_str);
- error:
- l_string_free(id_str);
- return NULL;
- }
- static void tls_finished(struct l_tls *tls)
- {
- char *peer_identity = NULL;
- if (tls->peer_authenticated) {
- peer_identity = tls_get_peer_identity_str(tls->peer_cert);
- if (!peer_identity) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "tls_get_peer_identity_str failed");
- return;
- }
- }
- /* Free up the resources used in the handshake */
- tls_reset_handshake(tls);
- TLS_SET_STATE(TLS_HANDSHAKE_DONE);
- tls->ready = true;
- tls->in_callback = true;
- tls->ready_handle(peer_identity, tls->user_data);
- tls->in_callback = false;
- l_free(peer_identity);
- tls_cleanup_handshake(tls);
- }
- static void tls_handle_handshake(struct l_tls *tls, int type,
- const uint8_t *buf, size_t len)
- {
- TLS_DEBUG("Handling a %s of %zi bytes",
- tls_handshake_type_to_str(type), len);
- switch (type) {
- case TLS_HELLO_REQUEST:
- if (tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in server mode");
- break;
- }
- if (len != 0) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "HelloRequest not empty");
- break;
- }
- /*
- * May be sent by the server at any time but "SHOULD be ignored
- * by the client if it arrives in the middle of a handshake"
- * and "MAY be ignored by the client if it does not wish to
- * renegotiate a session".
- */
- break;
- case TLS_CLIENT_HELLO:
- if (!tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in client mode");
- break;
- }
- if (tls->state != TLS_HANDSHAKE_WAIT_HELLO &&
- tls->state != TLS_HANDSHAKE_DONE) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- tls_handle_client_hello(tls, buf, len);
- break;
- case TLS_SERVER_HELLO:
- if (tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in server mode");
- break;
- }
- if (tls->state != TLS_HANDSHAKE_WAIT_HELLO) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- tls_handle_server_hello(tls, buf, len);
- break;
- case TLS_CERTIFICATE:
- if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- tls_handle_certificate(tls, buf, len);
- break;
- case TLS_SERVER_KEY_EXCHANGE:
- if (tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in server mode");
- break;
- }
- if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE);
- tls->pending.cipher_suite->key_xchg->handle_server_key_exchange(
- tls, buf, len);
- break;
- case TLS_CERTIFICATE_REQUEST:
- if (tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in server mode");
- break;
- }
- /*
- * Server sends this optionally so in the WAIT_HELLO_DONE
- * state we accept either this or a Server Hello Done (below).
- */
- if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE ||
- tls->cert_requested ||
- !tls->pending.cipher_suite->signature) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in current state "
- "or certificate check not supported "
- "in pending cipher suite");
- break;
- }
- tls_handle_certificate_request(tls, buf, len);
- break;
- case TLS_SERVER_HELLO_DONE:
- if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- tls_handle_server_hello_done(tls, buf, len);
- break;
- case TLS_CERTIFICATE_VERIFY:
- if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- tls_handle_certificate_verify(tls, buf, len);
- break;
- case TLS_CLIENT_KEY_EXCHANGE:
- if (!tls->server) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in client mode");
- break;
- }
- if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- /*
- * If we accepted a client Certificate message with a
- * certificate that has signing capability (TODO: check
- * usage bitmask), Certificate Verify is received next. It
- * sounds as if this is mandatory for the client although
- * this isn't 100% clear.
- */
- if (tls->peer_pubkey)
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY);
- else
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC);
- tls->pending.cipher_suite->key_xchg->handle_client_key_exchange(
- tls, buf, len);
- break;
- case TLS_FINISHED:
- if (tls->state != TLS_HANDSHAKE_WAIT_FINISHED) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Message invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- break;
- }
- if (!tls_verify_finished(tls, buf, len))
- break;
- if (tls->server) {
- const char *error;
- tls_send_change_cipher_spec(tls);
- if (!tls_change_cipher_spec(tls, 1, &error)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "change_cipher_spec: %s",
- error);
- break;
- }
- tls_send_finished(tls);
- }
- /*
- * On the client, the server's certificate is now verified
- * regardless of the key exchange method, based on the
- * following logic:
- *
- * - tls->ca_certs is non-NULL so tls_handle_certificate
- * (always called on the client) must have veritifed the
- * server's certificate chain to be valid and additionally
- * trusted by our CA.
- *
- * - the peer owns the end-entity certificate because:
- * either:
- *
- * * (RSA key exchange algorithm case) the correct
- * receival of this Finished message confirms the
- * posession of the master secret, it is verified by
- * both the successful decryption and the MAC of this
- * message (either should be enough) because we entered
- * the TLS_HANDSHAKE_WAIT_FINISHED state only after
- * encryption and MAC were enabled in ChangeCipherSpec.
- * To obtain the master secret the server must have been
- * able to decrypt the pre_master_secret which we had
- * encrypted with the public key from that certificate.
- *
- * * (ECDHE and DHE key exchange algorithms) server was
- * able to sign the client random together with the
- * ServerKeyExchange parameters using its certified key
- * pair.
- */
- if (!tls->server && tls->cipher_suite[0]->signature &&
- tls->ca_certs)
- tls->peer_authenticated = true;
- tls_finished(tls);
- break;
- default:
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Invalid message");
- }
- }
- LIB_EXPORT struct l_tls *l_tls_new(bool server,
- l_tls_write_cb_t app_data_handler,
- l_tls_write_cb_t tx_handler,
- l_tls_ready_cb_t ready_handler,
- l_tls_disconnect_cb_t disconnect_handler,
- void *user_data)
- {
- struct l_tls *tls;
- if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO))
- return NULL;
- tls = l_new(struct l_tls, 1);
- tls->server = server;
- tls->rx = app_data_handler;
- tls->tx = tx_handler;
- tls->ready_handle = ready_handler;
- tls->disconnected = disconnect_handler;
- tls->user_data = user_data;
- tls->cipher_suite_pref_list = tls_cipher_suite_pref;
- tls->min_version = TLS_MIN_VERSION;
- tls->max_version = TLS_MAX_VERSION;
- /* If we're the server wait for the Client Hello already */
- if (tls->server)
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
- else
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START);
- return tls;
- }
- LIB_EXPORT void l_tls_free(struct l_tls *tls)
- {
- enum handshake_hash_type hash;
- if (unlikely(!tls))
- return;
- if (tls->in_callback) {
- tls->pending_destroy = true;
- return;
- }
- l_tls_set_cacert(tls, NULL);
- l_tls_set_auth_data(tls, NULL, NULL);
- l_tls_set_domain_mask(tls, NULL);
- l_tls_set_cert_dump_path(tls, NULL);
- tls_reset_handshake(tls);
- tls_cleanup_handshake(tls);
- tls_reset_cipher_spec(tls, 0);
- tls_reset_cipher_spec(tls, 1);
- if (tls->record_buf)
- l_free(tls->record_buf);
- if (tls->message_buf)
- l_free(tls->message_buf);
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++)
- tls_drop_handshake_hash(tls, hash);
- if (tls->debug_destroy)
- tls->debug_destroy(tls->debug_data);
- if (tls->cipher_suite_pref_list != tls_cipher_suite_pref)
- l_free(tls->cipher_suite_pref_list);
- l_free(tls);
- }
- LIB_EXPORT void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len)
- {
- if (unlikely(!tls->ready)) {
- return;
- }
- tls_tx_record(tls, TLS_CT_APPLICATION_DATA, data, len);
- }
- bool tls_handle_message(struct l_tls *tls, const uint8_t *message,
- int len, enum tls_content_type type, uint16_t version)
- {
- enum handshake_hash_type hash;
- const char *error;
- switch (type) {
- case TLS_CT_CHANGE_CIPHER_SPEC:
- if (len != 1 || message[0] != 0x01) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "ChangeCipherSpec msg decode error");
- return false;
- }
- if (tls->state != TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "ChangeCipherSpec invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- return false;
- }
- if (!tls_change_cipher_spec(tls, 0, &error)) {
- TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
- "change_cipher_spec: %s", error);
- return false;
- }
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_FINISHED);
- return true;
- case TLS_CT_ALERT:
- /* Verify AlertLevel */
- if (message[0] != 0x01 && message[0] != 0x02) {
- TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0,
- "Received bad AlertLevel %i",
- message[0]);
- return false;
- }
- /*
- * On a fatal alert we are obligated to respond with a
- * fatal alert and disconnect but also not complain if
- * the connection has been torn down by the peer before
- * we were able to send our alert. However on a non-fatal
- * alert (warning) we're also allowed to panic and send
- * a fatal alert, then disconnect, so we do that
- * regardless of the alert level.
- */
- TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, message[1],
- "Peer sent a %s Alert: %s",
- message[0] == 0x02 ? "Fatal" : "Warning",
- l_tls_alert_to_str(message[1]));
- return false;
- case TLS_CT_HANDSHAKE:
- /* Start hashing the handshake contents on first message */
- if (tls->server && message[0] == TLS_CLIENT_HELLO &&
- (tls->state == TLS_HANDSHAKE_WAIT_HELLO ||
- tls->state != TLS_HANDSHAKE_DONE))
- if (!tls_init_handshake_hash(tls))
- return false;
- /*
- * Corner case: When handling a Certificate Verify or a
- * Finished message we need access to the messages hash from
- * before this message was transmitted on the Tx side so we
- * can verify it matches the hash the sender included in the
- * message. We save it here for that purpose. Everywhere
- * else we need to update the hash before handling the new
- * message because 1. we may need the new hash to build our
- * own Certificate Verify or Finished messages, and 2. we
- * update the message hash with newly transmitted messages
- * inside tls_tx_handshake which may be called as part of
- * handling incoming message, and if we didn't call
- * l_checksum_update before, the calls would end up being
- * out of order.
- */
- if (message[0] == TLS_CERTIFICATE_VERIFY ||
- message[0] == TLS_FINISHED)
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
- if (!tls->handshake_hash[hash])
- continue;
- tls_get_handshake_hash(tls, hash,
- tls->prev_digest[hash]);
- }
- /*
- * RFC 5246, Section 7.4.1.1:
- * This message MUST NOT be included in the message hashes
- * that are maintained throughout the handshake and used in
- * the Finished messages and the certificate verify message.
- */
- if (message[0] != TLS_HELLO_REQUEST)
- for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) {
- if (!tls->handshake_hash[hash])
- continue;
- l_checksum_update(tls->handshake_hash[hash],
- message, len);
- }
- tls_handle_handshake(tls, message[0],
- message + TLS_HANDSHAKE_HEADER_SIZE,
- len - TLS_HANDSHAKE_HEADER_SIZE);
- if (tls->pending_destroy) {
- l_tls_free(tls);
- return false;
- }
- return true;
- case TLS_CT_APPLICATION_DATA:
- if (!tls->ready) {
- TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0,
- "Application data message before "
- "handshake finished");
- return false;
- }
- if (!len)
- return true;
- tls->in_callback = true;
- tls->rx(message, len, tls->user_data);
- tls->in_callback = false;
- if (tls->pending_destroy) {
- l_tls_free(tls);
- return false;
- }
- return true;
- }
- return false;
- }
- LIB_EXPORT bool l_tls_start(struct l_tls *tls)
- {
- if (tls->max_version < tls->min_version)
- return false;
- if (!tls->cipher_suite_pref_list)
- return false;
- /* This is a nop in server mode */
- if (tls->server)
- return true;
- if (tls->state != TLS_HANDSHAKE_WAIT_START) {
- TLS_DEBUG("Call invalid in state %s",
- tls_handshake_state_to_str(tls->state));
- return false;
- }
- if (!tls_init_handshake_hash(tls))
- return false;
- if (!tls_send_client_hello(tls))
- return false;
- TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO);
- return true;
- }
- LIB_EXPORT void l_tls_close(struct l_tls *tls)
- {
- TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, 0, "Closing session");
- }
- LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs)
- {
- if (tls->ca_certs) {
- l_queue_destroy(tls->ca_certs,
- (l_queue_destroy_func_t) l_cert_free);
- tls->ca_certs = NULL;
- }
- if (ca_certs) {
- if (!l_key_is_supported(L_KEY_FEATURE_RESTRICT)) {
- TLS_DEBUG("keyctl restrict support missing, "
- "check kernel configuration");
- return false;
- }
- tls->ca_certs = ca_certs;
- }
- return true;
- }
- LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls,
- struct l_certchain *certchain,
- struct l_key *priv_key)
- {
- if (tls->cert) {
- l_certchain_free(tls->cert);
- tls->cert = NULL;
- }
- if (tls->priv_key) {
- l_key_free(tls->priv_key);
- tls->priv_key = NULL;
- tls->priv_key_size = 0;
- }
- if (certchain)
- tls->cert = certchain;
- if (priv_key) {
- bool is_public = true;
- tls->priv_key = priv_key;
- if (!l_key_get_info(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
- L_CHECKSUM_NONE, &tls->priv_key_size,
- &is_public) || is_public) {
- TLS_DEBUG("Not a private key or l_key_get_info failed");
- tls->cert = NULL;
- tls->priv_key = NULL;
- tls->priv_key_size = 0;
- return false;
- }
- tls->priv_key_size /= 8;
- }
- return true;
- }
- bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list)
- {
- struct tls_cipher_suite **suite;
- if (tls->cipher_suite_pref_list != tls_cipher_suite_pref)
- l_free(tls->cipher_suite_pref_list);
- if (!suite_list) {
- /* Use our default cipher suite preference list */
- tls->cipher_suite_pref_list = tls_cipher_suite_pref;
- return true;
- }
- tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *,
- l_strv_length((char **) suite_list) + 1);
- suite = tls->cipher_suite_pref_list;
- for (; *suite_list; suite_list++) {
- unsigned int i;
- for (i = 0; tls_cipher_suite_pref[i]; i++)
- if (!strcmp(tls_cipher_suite_pref[i]->name,
- *suite_list))
- break;
- if (tls_cipher_suite_pref[i])
- *suite++ = tls_cipher_suite_pref[i];
- else
- TLS_DEBUG("Cipher suite %s is not supported",
- *suite_list);
- }
- if (suite > tls->cipher_suite_pref_list)
- return true;
- TLS_DEBUG("None of the supplied suite names is supported");
- l_free(suite);
- tls->cipher_suite_pref_list = NULL;
- return false;
- }
- LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls,
- enum l_tls_version min_version,
- enum l_tls_version max_version)
- {
- tls->min_version =
- (min_version && min_version > TLS_MIN_VERSION) ?
- min_version : TLS_MIN_VERSION;
- tls->max_version =
- (max_version && max_version < TLS_MAX_VERSION) ?
- max_version : TLS_MAX_VERSION;
- }
- /**
- * l_tls_set_domain_mask:
- * @tls: TLS object being configured
- * @mask: NULL-terminated array of domain masks
- *
- * Sets a mask for domain names contained in the peer certificate
- * (eg. the subject Common Name) to be matched against. If none of the
- * domains match the any mask, authentication will fail. At least one
- * domain has to match at least one mask from the list.
- *
- * The masks are each split into segments at the dot characters and each
- * segment must match the corresponding label of the domain name --
- * a domain name is a sequence of labels joined by dots. An asterisk
- * segment in the mask matches any label. An asterisk segment at the
- * beginning of the mask matches one or more consecutive labels from
- * the beginning of the domain string.
- */
- LIB_EXPORT void l_tls_set_domain_mask(struct l_tls *tls, char **mask)
- {
- l_strv_free(tls->subject_mask);
- tls->subject_mask = l_strv_copy(mask);
- }
- LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc)
- {
- switch (desc) {
- case TLS_ALERT_CLOSE_NOTIFY:
- return "close_notify";
- case TLS_ALERT_UNEXPECTED_MESSAGE:
- return "unexpected_message";
- case TLS_ALERT_BAD_RECORD_MAC:
- return "bad_record_mac";
- case TLS_ALERT_DECRYPT_FAIL_RESERVED:
- return "decryption_failure_RESERVED";
- case TLS_ALERT_RECORD_OVERFLOW:
- return "record_overflow";
- case TLS_ALERT_DECOMPRESS_FAIL:
- return "decompression_failure";
- case TLS_ALERT_HANDSHAKE_FAIL:
- return "handshake_failure";
- case TLS_ALERT_NO_CERT_RESERVED:
- return "no_certificate_RESERVED";
- case TLS_ALERT_BAD_CERT:
- return "bad_certificate";
- case TLS_ALERT_UNSUPPORTED_CERT:
- return "unsupported_certificate";
- case TLS_ALERT_CERT_REVOKED:
- return "certificate_revoked";
- case TLS_ALERT_CERT_EXPIRED:
- return "certificate_expired";
- case TLS_ALERT_CERT_UNKNOWN:
- return "certificate_unknown";
- case TLS_ALERT_ILLEGAL_PARAM:
- return "illegal_parameter";
- case TLS_ALERT_UNKNOWN_CA:
- return "unknown_ca";
- case TLS_ALERT_ACCESS_DENIED:
- return "access_denied";
- case TLS_ALERT_DECODE_ERROR:
- return "decode_error";
- case TLS_ALERT_DECRYPT_ERROR:
- return "decrypt_error";
- case TLS_ALERT_EXPORT_RES_RESERVED:
- return "export_restriction_RESERVED";
- case TLS_ALERT_PROTOCOL_VERSION:
- return "protocol_version";
- case TLS_ALERT_INSUFFICIENT_SECURITY:
- return "insufficient_security";
- case TLS_ALERT_INTERNAL_ERROR:
- return "internal_error";
- case TLS_ALERT_USER_CANCELED:
- return "user_canceled";
- case TLS_ALERT_NO_RENEGOTIATION:
- return "no_renegotiation";
- case TLS_ALERT_UNSUPPORTED_EXTENSION:
- return "unsupported_extension";
- }
- return NULL;
- }
- const char *tls_handshake_state_to_str(enum tls_handshake_state state)
- {
- static char buf[100];
- switch (state) {
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_START)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO_DONE)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_FINISHED)
- SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_DONE)
- }
- snprintf(buf, sizeof(buf), "tls_handshake_state(%i)", state);
- return buf;
- }
- int tls_parse_certificate_list(const void *data, size_t len,
- struct l_certchain **out_certchain)
- {
- const uint8_t *buf = data;
- struct l_certchain *chain = NULL;
- while (len) {
- struct l_cert *cert;
- size_t cert_len;
- if (len < 3)
- goto decode_error;
- cert_len = *buf++ << 16;
- cert_len |= *buf++ << 8;
- cert_len |= *buf++ << 0;
- if (cert_len + 3 > len)
- goto decode_error;
- cert = l_cert_new_from_der(buf, cert_len);
- if (!cert)
- goto decode_error;
- if (!chain) {
- chain = certchain_new_from_leaf(cert);
- if (!chain)
- goto decode_error;
- } else
- certchain_link_issuer(chain, cert);
- buf += cert_len;
- len -= cert_len + 3;
- }
- if (out_certchain)
- *out_certchain = chain;
- else
- l_certchain_free(chain);
- return 0;
- decode_error:
- l_certchain_free(chain);
- return -EBADMSG;
- }
- LIB_EXPORT bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function,
- void *user_data, l_tls_destroy_cb_t destroy)
- {
- if (unlikely(!tls))
- return false;
- if (tls->debug_destroy)
- tls->debug_destroy(tls->debug_data);
- tls->debug_handler = function;
- tls->debug_destroy = destroy;
- tls->debug_data = user_data;
- return true;
- }
- LIB_EXPORT bool l_tls_set_cert_dump_path(struct l_tls *tls, const char *path)
- {
- l_free(tls->cert_dump_path);
- tls->cert_dump_path = path ? l_strdup(path) : NULL;
- return true;
- }
|