Code signing Tom Tervoort Code signing is een methode om gedistribueerde software te beveiligen en om de ontvanger van deze software een garantie te geven van authenticiteit en integriteit: dit houdt in dat de software afkomstig is van de juiste auteur en dat deze niet door derden is bewerkt. Het signeren van software heeft meerdere toepassingen: zo kan een bedrijf deze software onbezorgd over een onveilig kanaal sturen en/of deze software op een server zetten zonder bang te zijn dat deze wordt aangepast door een hack. De gebruiker kan er vervolgens vanuit gaan dat er geen derden malware aan dit programma hebben toegevoegd: zoals virussen, spionagemiddelen of mogelijkheden tot phishing dat uit betrouwbare bron lijkt te komen. De techniek wordt hierom vooral vaak gebruik voor het geautomatiseerd downloaden van updates. Deze dingen wordt bereikt door middel van een zogenaamde digitale handtekening: een asymmetrisch versleuteld certificaat dat iedereen kan lezen (d.m.v. de publieke sleutel) maar enkel de oorspronkelijke auteur (of preciezer: de bezitter van de geheime sleutel) zou moeten kunnen schrijven. Dit certificaat wordt bijgeleverd met de bijbehorende software-executable, -script of -installer en bevat een 'vingerafdruk' hiervan. Zo'n afdruk, vaak een cryptografische hash, kan vervolgens gebruikt worden om te controleren of de software exact hetzelfde is als op het moment dat deze afdruk daarvan gemaakt is. Het is natuurlijk belangrijk dat het praktisch onmogelijk is een aangepast of ander programma ook aan deze afdruk te laten voldoen. Om een handtekening van bedrijf X te kunnen lezen, is het vereist dat de gebruiker de publieke sleutel die daarbij hoort bezit om deze te kunnen lezen. Deze sleutel mag ook niet vervalst zijn, omdat dat aanvallers ook in staat kan stellen een valse handtekening bij valse software door jouw te laten accepteren.
Het mechanisme Om code signing uit te kunnen voeren, is er ten eerste een sleutelpaar nodig dat voor een asymmetrisch encryptiealgoritme kan worden gebruikt. Dit algoritme kan bijvoorbeeld RSA of ElGamal zijn. De private sleutel moet goed geheim gehouden worden terwijl de publieke sleutel op een veilige manier bij de beoogde gebruiker van de te signeren software dient te belanden (zie “Sleutelbeheer”). Naast een publieke sleutel, moet de ontvanger ook een programma bezitten om jouw software te downloaden, de handtekening te decrypten, de vingerafdruk te vergelijken. In het geval van een ongeldige handtekening of afdruk dient de gebruiker geïnformeerd te worden en mag de foute software niet uitgevoerd worden. Dit kan afgehandeld worden door bestaande architectuur die bijvoorbeeld bij het besturingssysteem wordt geleverd, maar dan moet deze wel vertrouwd worden. Daarnaast is het mogelijk hier eigen software voor te gebruiken, en die bij de public key te leveren. Als dit eenmaal een keer gebeurt is, kan voortaan al jouw software ondertekend naar gebruikers met een publieke sleutel worden gestuurd. Het is ook mogelijk een externe partij (zoals een certificaatautoriteit) het ondertekenen af te laten handelen. Hierbij geef je het sleutelbeheer uit handen maar introduceer je wel een nieuwe partij die vertrouwd dient te worden. Om software die je wilt distribueren te ondertekenen moet eerst de 'vingerafdruk' van het complete softwarepakket (zoals dit geleverd wordt) worden gemaakt. Het proces om een afdruk van een bestand te maken moet aan de eigenschap voldoen dat de kans dat twee verschillende bestanden dezelfde afdruk hebben praktisch nihil is. Daarnaast moeten aanvallers ook niet in staat zijn bewust een verschillend programma te creëren dat dezelfde vingerafdruk produceert. In de praktijk wordt voor het afnemen van de afdruk bijna altijd een cryptografisch hashingalgoritme gebruikt, zoals MD-5, bcrypt of iets uit de SHA-familie. Een 'goede' hashfunctie zou aan de vereiste eigenschap moeten voldoen. Na het maken van de afdruk kan de handtekening gemaakt en met de private sleutel geëncrypteerd worden, of die naar de partij die de versleutelingen doet gestuurd moet worden. Een alternatief, waarbij geen vingerafdruk nodig is, is het volledig versleutelen van de software; asymmetrisch encrypteren is echter duur, en voor een groot programma is dit vaak niet te doen.
1
Als de handtekening eenmaal gezet is, kan deze standaard bij deze versie van het stuk software geleverd. De ontvangers hoeven nu alleen nog maar het certificaat te ontsleutelen met de publieke sleutel en zowel de gegevens daarin als de vingerafdruk te controleren.
Wat is er mogelijk, en wat wordt beschermd? Wanneer code signing op een volledig correcte en veilige manier gebruikt wordt, de gebruikte hashing- en encryptiealgoritmen niet gekraakt of met de gebruikte sleutellengte te brute-forcen zijn, de private sleutel geheim blijft en de publieke sleutel op een veilige manier is verspreid, kunnen de volgende garanties worden gegeven: •
Authenticiteit: de ontvanger van de software kan controleren of deze van de juiste oorspronkelijke afzender komt, ongeacht de veiligheid van de verbinding en waar de software voorheen is gehost.
•
Integriteit: derden hebben na de ondertekening geen modificaties kunnen aanbrengen aan de software en deze is dus exact gelijk aan wat er bij de ontwikkelaar uit de deur is gegaan.
•
Onloochenbaarheid: de gebruiker kan achteraf bij bijvoorbeeld de rechter bewijzen dat (een specifieke versie van) de software in kwestie daadwerkelijk afkomstig is van een bepaald bedrijf, mochten die dat ontkennen.
De volgende zaken worden echter niet gegarandeerd door code signing: •
Bugs: de ontwikkelaar kan logischerwijs nog altijd (destructieve) fouten maken.
•
Absentie van malware, backdoors e.d.: er wordt enkel beschermt tegen het toevoegen van dit soort zaken na het ondertekenen van de software; daarvoor kan dat echter wel gebeuren door kwaadwillenden binnen het bedrijf of de instantie die ondertekend. De softwareontwikkelaar op zich hoeft, als die zijn producten ondertekend, natuurlijk ook niet per se betrouwbaar te zijn.
Desalniettemin zijn er voor code signing veel handige toepassingen, bijvoorbeeld: •
Een updatemechanisme van een virusscanner, OS of ander soort software: de publieke sleutel en het download- en validatiemechanisme zijn aanwezig in de oorspronkelijke versie, vervolgens kunnen op een veilige manier updates worden gedownload die van de softwaremaker afkomstig zijn.
•
Het bijhouden van 'software repositories': veel Linuxdistributies worden geleverd met toegang tot een softwaredepot vanwaar makkelijk een grote verscheidenheid aan software van gedownload kan worden. Als er geen code signing zou worden toegepast, en een aanvaller inbreekt in zo'n repository, kan er zeer veel schade aangericht worden omdat er nu malware kan worden toegevoegd aan allerlei soorten software die samen zeer veel gedownload worden. Door een veilige vorm van code signing hier toe te passen, is dit geen risico meer, ook als de server wordt gehackt. Bovendien kunnen allerlei 'mirrors' (alternatieve hosters van repositories) gebruikt worden die eigendom zijn van verschillende partijen zonder dat je die partijen (of hun beveiliging) hoeft te vertrouwen.
•
Het aan de gebruiker presenteren van de naam van de organisatie en het programma nadat ze dat van internet (of uit andere bron) hebben gedownload. Zo kunnen zij bepalen of deze gegevens kloppen en of zij het bedrijf in kwestie vertrouwen.
Het certificaat Wanneer je enkel een geëncrypteerde vingerafdruk mee levert is er lastig onderscheid te maken tussen verschillende producten die dezelfde geheime sleutel gebruiken. Dit is zeker een probleem wanneer er gebruik gemaakt wordt van een instantie als een certificaatautoriteit voor het versleutelen; maar anderzijds kan dit ook problemen opleveren tenzij je voor elke versie voor elk product een apart sleutelpaar gebruikt, wat vaak onpraktisch is. Om deze reden wordt er aan de software waar een vingerafdruk over wordt genomen ook een zogenaamd certificaat toegevoegd met extra informatie. Dit certificaat zou ook met de vingerafdruk mee versleuteld kunnen worden. De volgende eigenschappen zijn o.a. erg handig om in het certificaat te hebben staan:
2
•
Een uniek serienummer: mocht er een sleutel uitlekken of iets anders misgaan, dan zouden certificaten met een bepaald nummer op een zwarte lijst gezet kunnen worden.
•
Organisatienaam of -nummer: wanneer er sprake is van een certificaatautoriteit die software van meerdere bedrijven ondertekend moeten organisaties onderscheiden kunnen worden. Dit is ook belangrijk wanneer de organisatienaam aan de gebruiker gepresenteerd moet worden. Microsoft gebruikt bijvoorbneeld het Data Universal Numbering System (DUNS) om bedrijven te identificeren, omdat de organisatie hierachter wereldwijd bedrijven registreert.
•
Naam ondertekend programma: voorkomt dat het programma vervangen wordt door een ander, correct ondertekende, applicatie van dezelfde bron. Meestal niet iets waar aanvallers mee bereiken, tenzij degene die de ondertekeningen doet inzendingen niet goed controleert.
•
Versienummer applicatie: als dit niet bijgehouden zou worden, en er wordt een zwakheid in versie x van een programma aangetroffen, dan zouden aanvallers een gerepareerde nieuwe versie van deze software door versie x kunnen vervangen en deze zwakheid blijven benutten.
•
Verloopdatum: om de aangerichte schade te mitigeren die wordt aangericht door een uitgelekte sleutel kunnen handtekeningen hiermee ongeldig worden verklaart na een bepaalde tijd. Dit vereist wel een verversing van de alle al gezette handtekeningen en de sleutels, wat betekend dat de nieuwe publieke sleutel opnieuw gedistribueerd zal moeten worden (zie “Sleutelbeheer”).
•
De publieke sleutel: deze kan de ontvanger gebruiken om te controleren of de publieke sleutel die hij zelf bezit hiermee klopt. Ook kan dit gebruikt worden voor een niet optimaal veilige, maar soms wel afdoende, manier van sleuteldistributie (zie “Sleutelbeheer”).
De handtekening en de 'vingerafdruk' Een belangrijk aspect van het ondertekeningsproces is de vingerafdruk: een rijtje bits dat de data-integriteit van een bestand of een stuk software garandeert. We noemen deze functie die de vingerafdruk maakt F en een arbitraire mogelijke invoer van deze functie x. F(x) is dus de vingerafdruk zelf. F moet aan de volgende eigenschappen voldoen:
1. F(x) dient een constante (maximale) lengte te hebben, ongeacht de lengte van x. Deze lengte n dient wel zo lang te zijn dat deze met de huidige (en het liefst ook de tot zover mogelijk toekomstige) stand van techniek te brute-forcen is. Hoewel een brutenkrachtaanval op een vingerafdruk op zich onzinnig lijkt te zijn, zou de mogelijkheid daartoe wel kunnen betekenen dat men ongeveer 2 n-1 variaties op een ongeldig programma zou kunnen maken totdat er een y is gevonden waarvoor geldt dat F(x) = F(y). Dit is niet het enige waar rekening mee moet worden gehouden bij een beperkte lengte: het is namelijk zo dat hoe kleiner de n is, hoe meer botsingen kunnen ontstaan uit verschillende invoeren; dit maakt het lastiger de punten hieronder af te dwingen.
2. F moet 'zwak botsingsvrij' zijn: dit houdt in dat wanneer x bekend is het ondoenlijk is een y ongelijk aan x te vinden waarvoor geldt dat F(x) = F(y). Als een aanvaller dit wel zou kunnen, zou die een techniek om y te vinden waarschijnlijk ook kunnen gebruiken een kwaadaardig programma z te veranderen in een z' waarvoor geldt dat F(x) = F(z') en dat het effect van z' gelijk is aan dat van z.
3. F moet ook 'sterk botsingsvrij' zijn, wat betekend dat het niet mogelijk is een paar (x,y) te genereren waarvoor geldt x ≠ y en F(x) = F(y). Een aanvaller zou dan in theorie een x die één of andere manier gevalideerd en ondertekend is kunnen vervangen door een kwaadaardige y. Hoewel het waarschijnlijk, in een systeem dat wel zwak maar niet sterk botsingsvrij is, praktisch ondoenlijk is een paar te genereren waarvan beide effectieve programma's zijn met een gewenst effect, kun je hier niet zeker van zijn; zeker gezien je altijd willekeurige of arbitraire data in een executable kan stoppen. Wanneer de hash niet lang genoeg is (eigenschap 1) is het mogelijk om door middel van een verjaardagsaanval een dergelijk paar te creëren: door voor een hoop willekeurige waarden voor zowel x als y te blijven genereren en dezen te hashen wordt er naar verwachting na 2n/2 pogingen een botsing gevonden.
4. Het moet ondoenlijk zijn F te inverteren: wanneer elke F(x) herleidbaar is tot één of andere y waarvoor F(x) = F(y) is het meestal extreem onwaarschijnlijk dat x = y en heb je dus de mogelijkheid een
3
programma te vervangen. Hoewel y waarschijnlijk geen nuttig programma zal representeren, zou een arbitrair stuk software dat wel wordt toegestaan misschien wel gebruikt kunnen worden om een systeem te corrumperen (bijvoorbeeld bij het toepassen van een update) of om ergens een buffer overflow o.i.d. Te bewerkstelligen. Je wilt dit risico liever niet nemen. Als een hashfunctie aan eigenschap 3 (sterke botsingsvrijheid) voldoet, dan voldoet die ook aan de andere drie eigenschappen omdat door het doorbreken van één van deze eigenschappen ook sterke botsingsvrijheid kan worden doorbroken.
Checksums Voor het behouden van data-integriteit bij bijvoorbeeld fysieke verbindingen waarop gegevensverlies zou kunnen optreden wordt vaak een zogenaamde checksum gebruikt. Oorspronkelijk was zo'n checksum een simpele sommatie van elke byte (of een ander woord van een bepaald aantal bits) in een bericht, maar er zijn ook alternatieve vergelijkbare operaties waarvan de kans op een toevallige botsing kleiner is. Een voorbeeld van het gebruik van een checksum is het TCP-protocol, dat bedoelt is om pakketjes waarvan er door ruis op de de transmissielaag één of meerdere bits veranderd zijn te detecteren en weg te gooien. De meeste checksum-algoritmes zijn er erop gericht erg snel uit te voeren te zijn en goed te zijn in het detecteren van accidentele fouten in een bestand die veroorzaakt zijn door een bug of een (vaak willekeurige) transmissiefout. Ze zijn echter niet ontworpen met een aanvaller in het achterhoofd, die geen willekeurige maar heel doelbewuste veranderingen aan het bestand in kwestie aanbrengt. Hierdoor zal bijna geen enkele checksummethode (dat ontworpen is om willekeurige fouten te detecteren en zo efficiënt mogelijk dient te zijn) aan ook maar één van de vier bovenstaande eigenschappen voldoen. Checksums zijn dus slechte methoden om vingerafdrukken te nemen. Andersom is dit echter niet helemaal waar, een goede cryptografische hashfunctie (zie hieronder) kan ook prima als checksum worden gebruikt: omdat deze goed beschermen tegen intentioneel opgezochte botsingen, zullen ze al helemaal goed zijn in het detecteren van accidentele en willekeurige mutaties in de invoer. Ze zijn echter vaak ook een stuk minder efficiënt. Dat weerhoudt velen er echter niet van hashfuncties hiervoor te gebruiken: versiebeheersysteem Git gebruikt bijvoorbeeld de hashfunctie SHA-1 als checksummethode (en voor het generen van unieke identifiers).
Cryptografische hashfuncties Een cryptografische hashfunctie is een algoritme dat er speciaal voor ontworpen is om niet inverteerbaar te zijn (eigenschap 4 voor een goede vingerafdruk-methode). Dit betekent niet dat het theoretisch onmogelijk is dezen te inverteren (je kunt namelijk altijd inputs brute-forcen) maar dat het met de huidige techniek ondoenlijk is dat binnen een eeuw of langer te doen. Deze functies komen van pas als je niet wilt dat mensen x te weten komen maar wel dat mensen aan de hand van F(x) kunnen bepalen of de y die ze al bezitten gelijk is aan x. Dit is erg handig voor het veilig opslaan van wachtwoorden. Goede hashfuncties dienen, naast eigenschap 4, ook aan eigenschap 3 te voldoen om andersoortig misbruik (bijvoorbeeld het genereren van een alternatief wachtwoord dat ook toegang geeft) te voorkomen; en eigenschap 3 impliceert eigenschappen 1, 2 en 4. Oftewel: een veilige fingerprintingfunctie voldoet aan dezelfde eigenschappen als een goede hashfunctie en vice-versa, ze zijn praktisch equivalent. Vanwege eigenschap 4 kan hashing kan ook gezien worden als een vorm van éénrichtingsencryptie. Om deze reden zou je een hashfunctie die enkel 'blokken' data van een constante (maar niet te kleine) lengte c versleuteld door middel van chainingmethode (zoals gebruikt voor DES of AES) op een langer stuk data kunnen toepassen. Vervolgens kan het laatste blok genomen als de uiteindelijke hash. Van tevoren moet wel de invoer aangevuld worden met bijvoorbeeld nullen om een lente te krijgen die een veelvoud van c is. Ook moet nu de oorspronkelijke lengte van de invoer meegehasht worden (anders zou een invoer van lengte nc – i dezelfde hash krijgen als een invoer met lengte nc met op het einde i nullen).
MD5 MD5 was (en is nog steeds) een veelgebruikt hashalgoritme die hashes produceert van 128 bits. Het algoritme wordt toegepast op blokken van 512 bits. Per blok wordt er een getal van 128 bits bijgehouden (beginnend met een speciale constante) en dit wordt afhankelijk van de invoer gemanipuleerd tot het uiteindelijke resultaat.
4
In de bovenstaande afbeelding is een MD5-operatie te zien. MD5 bestaat uit 64 operaties; 16 per ronde. A, B, C, en D zijn de vier woorden van elk 32 bits uit het statusgetal van 128 bits. F is één van vier mogelijke non-lineaire functies (hier zijn dat combinaties van de bitwise logische operaties AND, OR, XOR en NOT) die per ronde gevarieerd worden. Mi bevat een blok van 32 bits uit de invoer en Ki is een van de ronde afhankelijke constante. <<<s is een bitrotatie naar links waarvan het aantal plaatsen s ook per ronde varieert. In de vierkanten met een + erin vindt een optelling modulo 232 plaats. MD5 ziet er veelbelovend uit en is ook een tijd veel gebruikt. Ondertussen is het echter grotendeels gekraakt, en de Internet Engineering Task Force geeft in RFC 6151 expliciet aan dat het gebruik van MD5 voor het doel van digitale handtekeningen niet meer acceptabel is. De reden is dat het tegenwoordig erg makkelijk is om botsingen binnen MD5 te veroorzaken, wat men in het geval van code signing natuurlijk altijd wilt voorkomen. De eerste succesvolle botsingsaanval werd in 1996 (vier jaar na de eerste publicatie van MD5) al gevonden. In 2005 slaagden onderzoekers erin twee X.509-certificaten (o.a. gebruikt voor SSL) te creëren die eenzelfde MD5hash opleverden. In 2008 lukte het onderzoekers bestaande certificaten te modificeren. Hieruit bleek nogmaals dat MD5 in de praktijk ook gewoon onveilig was voor het gebruik van digitale handtekeningen. Eén zwakheid van MD5 is de gelimiteerde grootte van de hash. Omdat deze 128 bits is is er dus in O(2 64) een verjaardagsaanval uit te voeren, wat met de huidige stand van techniek haalbaar is. Het is ook mogelijk willekeurige data aan twee verschillende bestanden (bijvoorbeeld een authentiek en een vervalst programma) te blijven toevoegen en constant te hashen totdat de hashes toevallig overeen komen. Handig aan deze aanval is dat de twee programma's (die misschien megabytes aan data bevatten) maar eenmalig door de hashfunctie hoeven worden gehaald: de MD5-status op dit punt kan dan onthouden worden en er hoeft voor elke toevoeging niet steeds opnieuw begonnen te worden. Hier gebruik van makend is het al mogelijk een MD5handtekening te vervalsen na zo'n 250 MD5-evaluaties, door op creatieve wijze toevoegingen te zoeken. Zo'n zogenaamde chosen-prefix attack wel vrij makkelijk tegen te gaan: voer de hashfunctie simpelweg tweemaal op de gehele invoer uit. Als je het hier echter van moet hebben kun je beter een andere hashfunctie kiezen.
SHA-1 SHA staat voor 'Secure Hash Algorithm' en is ontwikkeld door de NSA. SHA-1 is hetzelfde als de oorspronkelijke variant SHA-0, behalve een kleine wijziging. Het systeem is vergelijkbaar met MD5, alleen zijn de hash en de staat nu 160 bits lang. Deze wordt per iteratie onderverdeeld in vijf blokken van 32 bits en op de volgende wijze gemanipuleerd:
5
De symbolen betekenen hetzelfde als bij de beschrijving van MD5. Er worden wel andere F-functies gebruikt en de grootte van de rotaties veranderd niet. Om een verjaardagsaanval op SHA-1 uit te voeren zijn 2160/2 = 280 evaluaties van de functie nodig. Dit is net op de grens van wat er wordt gezien als acceptabel. Verder bestaan er allerlei theoretische aanvallen gevonden om deze tijd te verbreken, waaronder een (nog onder discussie staande) methode die zo'n 2 57 evaluaties vereist. Geen van deze aanvallen is echter nog in de praktijk toegepast. Men kan daarom ook zeggen dat SHA-1 op het moment nog veilig is, al zou daar in de nabije toekomst verandering in kunnen komen. Het gebruik van de hashfunctie is voor digitale handtekeningen dus ook niet aan te raden. SHA-1 is opgevolgd door SHA-2, die uit een verzameling verschillende hashfuncties bestaat. Geen van die functies is noch in theorie, noch in de praktijk, gekraakt.
Asymmetrische encryptie Het meest gebruikte asymmetrische encryptiealgoritme voor het versleutelen van de vingerafdruk is RSA, gevolgd door ElGamal. We gaan hier uit van RSA, maar in principe gelden voor ElGamal dezelfde of vergelijkbare overwegingen. Van RSA is het (mits correct geïmplementeerd, en waarbij de encryptie-exponent hoog genoeg is, padding wordt toegepast e.d.) in principe enkel te kraken is door het ontbindingen van een uit twee priemgetallen samengesteld getal in deze priemfactoren. De geheime sleutel brute-forcen is een manier om dit te doen. Er is echter nog geen enkel algoritme bekend dat dit in polynomiale tijd kan oplossen. Het is ook niet bekend of zo'n algoritme bestaat (mocht het zo zijn dat P = NP, dan bestaat dit in ieder geval wél; als P ≠ NP is dat echter geen garantie dat het niet bestaat) en wiskundigen zijn er naar jaren zoeken in ieder geval nog steeds niet in geslaagd er één te vinden. Ondanks deze vrij sterke eigenschap van RSA, zijn er nog steeds aanvalspunten: •
Toch factoren ontbinden: als de sleutel niet groot genoeg is, is het nog steeds mogelijk om een algoritme met exponentiële complexiteit te gebruiken. Op dit moment is de grootst gekraakte sleutel 768 bits. Veel RSA-implementaties gebruiken nog 1024 bits. Het wordt daarom ook aangeraden om 2048-bits sleutels te gebruiken, gezien je daar waarschijnlijk nog heel wat jaren goed mee zit. Let ook op dat als er eenmaal één priemfactor gevonden is, de tweede door een simpele deling te verkrijgen is.
•
Side-channel aanvallen: sleutels zouden achterhaald kunnen worden door encryptie-operaties te verstoren of te timen. Bijvoorbeeld in het geval van een gestolen smartcard.
•
Implementatiefouten: gezien je weet wat het resultaat van een decryptie in het geval van code signing zou moeten zijn (namelijk een geldige vingerafdruk die je zelf ook kan berekenen), zou je implementatiefouten kunnen benutten om ervoor te zorgen dat deze decryptie wordt opgeleverd; ook al ken je de sleutel niet.
•
De random number generator: als deze enigszins voorspelbaar is, is het raden van de sleutel een stuk makkelijker.
Sleutelbeheer Om asymmetrische encryptie te kunnen toepassen, moet je er wel eerst voor zorgen dat de publieke sleutel bij de
6
gebruiker terecht komt, en dat de geheime sleutel ook daadwerkelijk geheim blijft. Als een aanvaller namelijk jouw geheime sleutel in handen krijgt óf jouw publieke sleutel door een eigen exemplaar weet te vervangen, dan kan de aanvaller zich als jou voordoen en allerlei narigheid aan jouw door je gebruikers vertrouwde software toevoegen.
Certificaat- en andere autoriteiten De meest gebruikte methode om te vermijden een sleutel geheim te hoeven houden is door het encryptieproces en sleutelbeheer over te laten aan zogenaamde CA's en de 'public key infrastructure' gebruiken voor het verspreiden van de publieke sleutel; die waarschijnlijk al als onderdeel van het operating system of browser van de gebruiker te vinden is. Het ondertekeningsproces dat hierbij hoort is ook gestandaardiseerd en veelgebruikt, en heeft daardoor een kleinere kans om kwetsbaarheden te bevatten dan een eigen systeem. Naast CA's worden ook vaak andere instanties gebruikt die zich met code signing bezighouden. Zowel Microsoft, Apple en de bedrijven achter verscheidene Linuxdistributies hebben faciliteiten om dit voor jouw te regelen. Het nadeel van het betrekken een extra partij is wel dat dit een nieuwe groep toevoegt die vertrouwt dient te worden. Bovendien zijn dit soort bedrijven een zeer aantrekkelijk doelwit voor aanvaller, en zou een succesvolle hack op hen (zoals bijvoorbeeld bij DigiNotar) ook jouw schade kunnen berokkenen.
Publieke sleuteldistributie Wanneer er geen gebruik wordt gemaakt van een certificaatautoriteit, OS-ontwikkelaar of andere externe partij waarvan de publieke sleutels waarschijnlijk al bij de doelgroep aanwezig zijn, dient er een manier gevonden te worden om de publieke sleutel onder de gebruikers van jouw ondertekende software te verspreiden. Hiervoor zijn verschillende technieken: •
Gebruik enkel code signing op updates en distribueer de standaardversie van de software samen met de public key op alternatieve wijze waarvan je aanneemt dat deze veilig genoeg is: bijvoorbeeld d.m.v. een cd in de winkel, een website (die beveiligt is via HTTPS, en weer een andere handtekening) of op bestelling.
•
Wanneer software gericht is op een specifieke klant, kunnen sleutels persoonlijk afgeleverd worden; bijvoorbeeld tijdens de eerste installatie of overdracht van de software.
•
Verplicht het gebruik van een vertrouwd kanaal om te verbinden met een vertrouwde host voor het verkrijgen van de sleutel. Vervolgens kunnen andere, niet per se veilige of vertrouwde, hosts gebruikt worden voor de daadwerkelijke software. Wanneer je voor je software meerdere externe 'mirrors' gebruikt om bandbreedte te besparen, zou je één eigen vertrouwde bron enkel voor sleutelverspreiding kunnen gebruiken.
•
Wanneer een gebruiker software van jou download maar nog niet de publieke sleutel die bij jouw bedrijf hoort bezit, kan deze overgenomen worden uit het certificaat (zie “Het certificaat”). Dit is niet helemaal veilig, omdat een aanvaller tijdens deze eerste download nog wel de software en/of de publieke sleutel zou kunnen vervalsen. Dit risico kan echter aanvaardbaar zijn als je verwacht dat aanvallers er de eerste keer meestal niet bij zullen zijn. Wat soms ook gedaan wordt is het geven van een visuele representatie van de publieke sleutel tijdens de eerste download; dan zou de gebruiker via een ander kanaal deze kunnen controleren als hij iets niet vertrouwd.
Ook belangrijk is dat, naast de publieke sleutel, ook een applicatie wordt verspreid die de handtekeningen controleert. Deze kan met de sleutel meegeleverd worden, of er kan een bestaande architectuur voor worden gebruikt: bijvoorbeeld een 'package manager' zoals die aanwezig is in veel Linuxdistributies.
Geheimhouding private sleutel Wanneer je zelf sleutels beheert, dienen maatregelen getroffen te worden om de geheime sleutel niet uit te laten lekken. Het liefst zou je deze in een kluis leggen, maar de sleutel moet wel constant gebruikt worden om nieuwe software te ondertekenen. De volgende maatregelen kunnen onder andere worden getroffen: •
Let op dat medewerkers van het bedrijf ook kwade bedoelingen kunnen hebben, of misleid kunnen worden door een phishingmail of vriendelijk ogende monteur die even een wachtwoord nodig heeft om een probleem op te lossen. Een private key is zeer gevoelige informatie en dient ook fysiek als zodanig
7
behandelt te worden. •
Stop de sleutel op een smartcard en laat deze de encrypties doen. Omdat je maar één encryptie per software release hoeft te doen, hoeft deze meestal niet zo efficiënt te zijn.
•
Sla de sleutel op in een aparte terminal die geen verbinding heeft met het internet. Wanneer er een release wordt gedaan moet vervolgens iemand fysiek de te ondertekenen software op een flashdrive meenemen of zelfs handmatig moeten invoeren, wat natuurlijk een stuk onpraktischer wordt naarmate er meer releases plaatsvinden. Daarnaast zou een USB-stick of een vergelijkbaar medium virussen kunnen bevatten; zelfs als het OS van de terminal daar tegen bestand zou moeten zijn is het misschien geen slecht idee om de informatie op deze flashdrives na gebruik te wissen, zodat sleutels in ieder geval niet naar buiten zouden kunnen lekken.
•
Als de sleutel toch op een met de buitenwereld verbonden server staat, probeer dan deze verbindingen zoveel mogelijk te beperken door bijvoorbeeld onnodige poorten af te sluiten. Gebruik zoveel mogelijk faciliteiten die het operating system biedt om data niet makkelijk leesbaar te houden.
•
Ververs sleutels om de zoveel tijd en voeg een houdbaarheidsdatum toe aan certificaten. Nieuwe publieke sleutels kunnen met de voorafgaande sleutel ondertekend worden. Wanneer er nu een geheime sleutel zou uitlekken zou je de schade kunnen beperken door de hierdoor getekende certificaten als ongeldig te verklaren. Degenen die niet op de hoogte zijn van deze ongeldigheid zullen vanzelf stoppen met het accepteren van certificaten die over datum zijn. Een probleem is nu wel dat, wanneer een aanvaller een sleutel in bezit heeft, die zelf een houdbaarheidsdatum zou kunnen toevoegen die in de toekomst ligt. Dit is lastig te voorkomen, maar het kan helpen af te dwingen dat houdbaarheidsdata niet meer dan een bepaalde hoeveelheid tijd in de toekomst liggen.
Zelfs als de geheime sleutel zeer goed beveiligt is en ook het gehele proces van code signing in orde is, zou een aanvaller nog steeds vergelijkbare schade kunnen aanrichten door zich toegang tot jouw source code te verschaffen en daar onwenselijke aanpassingen in aan te brengen. Dat is weliswaar makkelijker te detecteren, maar wanneer je eenmaal een correct ondertekende maar gecompromitteerde update naar alle klanten stuurt heb je een probleem.
Aanvallen Het is gebleken dat code signing op de volgende punten kan worden aangevallen: 1. De vingerafdruk: door willekeurige data aan vervalste software toe te voegen kan er na hashing een botsing ontstaan. Door het begin van het programma gelijk te laten zijn aan de bonafide versie kan dit een stuk efficiënter gemaakt worden, en daar deze bonafide versie zelf te kiezen kan een nog snellere verjaardagsaanval worden uitgevoerd. De effectiviteit hiervan wordt bepaald door de hashlengte en kwaliteit van het algoritme. MD5 is een goed voorbeeld van een veelgebruikte maar daadwerkelijk onveilige hashfunctie. 2. Het certificaat: bij het gebrek aan zaken als de organisatienaam en softwareversie zou een aanvaller zijn software door dezelfde instantie als het doelwit kunnen laten ondertekenen, en vervolgens een wisseltruc uithalen. Als het certificaat voorspelbaar is en het hashingalgoritme zwak, zouden botsingsaanvallen met valse certificaten gemakkelijker kunnen worden. 3. De asymmetrische encryptie: RSA zou aangevallen kunnen worden mocht iemand snel priemfactoren kunnen ontbinden of wanneer de sleutel niet groot genoeg is. Gebruikmaken van implementatiefouten of een slechte random number generator heeft vaak meer succes. 4. De geheime sleutel: deze kan gestolen worden. 5. De publieke sleutel: deze moet eerst bij de gebruiker bekend zijn. Als een aanvaller die echter kan vervangen door zijn exemplaar kan die vervolgens al jouw software ondertekenen. 6. De controleur van de vingerdrukken: als de applicatie die controleert of een vingerafdruk klopt op de één of andere manier voor de gek gehouden kan worden om foute handtekeningen te accepteren is de aanvaller binnen. Een aantal voorbeelden van aanvallen die hebben plaatsgevonden op één of meer van deze punten: •
(punt 1, 2, 6) Recent werd bekend dat het Flame-virus, vrij zeker afkomstig van de Amerikaanse en
8
Israëlische overheden, een botsingsaanval toepaste op het updatemechanisme van Windows. Windows ondersteund nog het gebruik van het onveilige MD5 om vingerafdrukken te nemen, waardoor het creëren van een botsing mogelijk werd. Verder waren houdbaarheidsdata en serienummers in het certificaat makkelijk te raden, en aan een ongebruikt en ongecontroleerd invoerveld kon informatie uit een ander geldig certificaat gekopieerd worden; hierdoor leek het begin van het neppe certificaat op dat van een andere geldige en werd de botsingsaanval vergemakkelijkt. •
(punt 6) De Nintendo Wii-spelcomputer gebruikt code signing om enkel gelicenseerde spellen toe te staan. De hashing en encryptie waren in orde, alleen werd voor het vergelijken van de vingerafdruk in de handtekening de C-functie strncpy gebruikt, die stopte met vergelijken bij de eerste 0-byte. Hierdoor konden hackers met gemak een programma produceren waarvan de hash met acht nulbits begon (een paar honderd hashpogingen zijn meer dan genoeg) en deze laten vergelijken met een geldige handtekening die hier ook mee startte.
•
(punt 4) De geheime sleutel van Yahoo!'s Axis browser bevond zich in de code van het programma zelf en was dus per ongeluk openbaar gemaakt.
•
(punt 6) De iPhone gebruikt code signing om te controleren of applicaties door Apple zijn goedgekeurd. In de browser en kernel van het apparaat zaten echter bugs waardoor met behulp van een buffer overflow kernelcode kon worden uitgevoerd en de controleur van de vingerafdrukken kon worden uitgeschakelt.
Conclusie Code signing is een handige techniek om gebruikers het vertrouwen te kunnen geven dat er met jouw software en updates, na een ondertekening, niet is geknoeid. Het signeren kan zelf gedaan worden of overgelaten worden aan een certificaatautoriteit of andere vertrouwde instantie. Belangrijk is het creëren van een 'vingerafdruk' van alle code met behulp van een 'sterk botsingsvrij' hashingalgoritme, en het asymmetrisch encrypteren hiervan met behulp van bijvoorbeeld RSA. Ook dient de correctheid van deze vingerafdruk goed afgedwongen te worden. Er zijn echter wel veel punten waarop het mechanisme aangevallen kan worden: er kan o.a. een hashbotsing veroorzaakt worden waardoor twee stukken software dezelfde vingerafdruk hebben, sleutels kunnen uitlekken en implementatiefouten kunnen benut worden. Desalniettemin is de techniek zeer belangrijk voor het veilig gebruik van software repositories en updatesystemen. Door het systeem correct en zorgvuldig te gebruiken ben je ook niet meer afhankelijk van de veiligheid van de servers waarop jouw software staat gehost en wordt veilige distributie vergemakkelijkt.
Bronnen Gerard Tel, Cryptografie: Beveiliging van de digitale maatschappij, hoofdstuk 7 (Digitale handtekeningen) MSDN (Microsoft), Introduction to code signing, http://msdn.microsoft.com/en-us/library/ms537361.aspx Deb Shinder, Code signing: Is it a Security feature?, http://www.windowsecurity.com/articles/Code-Signing.html Website versiebeheersysteem Git, http://git-scm.com/ Wikimedia Commons , https://commons.wikimedia.org/wiki/Main_Page S. Turner, L. Chen, Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms (RFC 6151), https://tools.ietf.org/html/rfc6151 Hans Dobbertin, The Status of MD5 After a Recent Attack, ftp://ftp.rsasecurity.com/pub/cryptobytes/crypto2n2.pdf Marc Stevens, Arjen Lenstra, Benne de Weger, Colliding X.509 Certificates based on MD5-collisions, http://www.win.tue.nl/~bdeweger/CollidingCertificates/ Jonathan Ness (MSRC Engineering), Flame malware collision attack explained https://blogs.technet.com/b/srd/archive/2012/06/06/more-information-about-the-digital-certificates-used-to-signthe-flame-malware.aspx SecurityPark, Code Signing becomes a topic of growing concern, http://www.securitypark.co.uk/security_article267672.html
9