1 /*
2 Copyright (C) 2011-2014 Yubico AB. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "oathpage.h"
30 #include "yubikeyutil.h"
31 #include "yubikeyfinder.h"
32 #include "yubikeywriter.h"
33 #include "ui_oathpage.h"
34 #include "ui/helpbox.h"
35 #include "ui/confirmbox.h"
36
37 #include <QDebug>
38 #include <QSignalMapper>
39 #include <QSettings>
40 #include <QDateTime>
41 #include <QTableWidgetItem>
42 #include <QRadioButton>
43
44 #define OATH_FIXED_NUMERIC 0
45 #define OATH_FIXED_MODHEX1 1
46 #define OATH_FIXED_MODHEX2 2
47 #define OATH_FIXED_MODHEX 3
48
49 #define MOVING_FACTOR_ZERO 0
50 #define MOVING_FACTOR_FIXED 1
51 #define MOVING_FACTOR_RAND 2
52
OathPage(QWidget * parent)53 OathPage::OathPage(QWidget *parent) :
54 QStackedWidget(parent),
55 ui(new Ui::OathPage)
56 {
57 ui->setupUi(this);
58
59 m_customerPrefix = -1;
60 memset(&m_pubId, 0, sizeof(m_pubId));
61 m_pubIdMUI = 0;
62 m_ykConfig = 0;
63 m_keyPresent = false;
64 clearState();
65
66 //Connect pages
67 connectPages();
68
69 //Connect help buttons
70 connectHelpButtons();
71
72 //Connect other signals and slots
73 connect(YubiKeyFinder::getInstance(), SIGNAL(keyFound(bool, bool*, int)),
74 this, SLOT(keyFound(bool, bool*)));
75
76 connect(ui->quickWriteConfigBtn, SIGNAL(clicked()),
77 this, SLOT(writeQuickConfig()));
78 connect(ui->advResetBtn, SIGNAL(clicked()),
79 this, SLOT(resetAdvPage()));
80
81 connect(ui->advMovingFactorSeedTxt, SIGNAL(editingFinished()),
82 this, SLOT(on_advMovingFactorSeedTxt_editingFinished()));
83
84 connect(ui->advHotpLen6Radio, SIGNAL(clicked()),
85 this, SLOT(hotpLen_clicked()));
86 connect(ui->advHotpLen8Radio, SIGNAL(clicked()),
87 this, SLOT(hotpLen_clicked()));
88 connect(ui->quickHotpLen6Radio, SIGNAL(clicked()),
89 this, SLOT(hotpLen_clicked()));
90 connect(ui->quickHotpLen8Radio, SIGNAL(clicked()),
91 this, SLOT(hotpLen_clicked()));
92
93 //Load settings
94 loadSettings();
95
96 ui->advResultsWidget->resizeColumnsToContents();
97 }
98
~OathPage()99 OathPage::~OathPage() {
100 if(m_ykConfig != 0) {
101 delete m_ykConfig;
102 m_ykConfig = 0;
103 }
104 delete ui;
105 }
106
107 /*
108 Common
109 */
110
connectPages()111 void OathPage::connectPages() {
112 //Map the values of the navigation buttons with the indexes of
113 //the stacked widget
114
115 //Create a QMapper
116 QSignalMapper *mapper = new QSignalMapper(this);
117
118 //Connect the clicked signal with the QSignalMapper
119 connect(ui->quickBtn, SIGNAL(clicked()), mapper, SLOT(map()));
120 connect(ui->quickBackBtn, SIGNAL(clicked()), mapper, SLOT(map()));
121
122 connect(ui->advBtn, SIGNAL(clicked()), mapper, SLOT(map()));
123 connect(ui->advBackBtn, SIGNAL(clicked()), mapper, SLOT(map()));
124
125 //Set a value for each button
126 mapper->setMapping(ui->quickBtn, Page_Quick);
127 mapper->setMapping(ui->quickBackBtn, Page_Base);
128
129 mapper->setMapping(ui->advBtn, Page_Advanced);
130 mapper->setMapping(ui->advBackBtn, Page_Base);
131
132 //Connect the mapper to the widget
133 //The mapper will set a value to each button and
134 //set that value to the widget
135 //connect(pageMapper, SIGNAL(mapped(int)), this, SLOT(setCurrentIndex(int)));
136 connect(mapper, SIGNAL(mapped(int)), this, SLOT(setCurrentPage(int)));
137
138 //Set the current page
139 m_currentPage = 0;
140 setCurrentIndex(Page_Base);
141 }
142
setCurrentPage(int pageIndex)143 void OathPage::setCurrentPage(int pageIndex) {
144 //Page changed...
145
146 m_currentPage = pageIndex;
147
148 switch(pageIndex){
149 case Page_Quick:
150 resetQuickPage();
151 break;
152 case Page_Advanced:
153 resetAdvPage();
154 break;
155 }
156
157 setCurrentIndex(pageIndex);
158
159 //Clear state
160 m_keysProgrammedCtr = 0;
161 clearState();
162 }
163
connectHelpButtons()164 void OathPage::connectHelpButtons() {
165 //Map the values of the help buttons
166
167 //Create a QMapper
168 QSignalMapper *mapper = new QSignalMapper(this);
169
170 //Connect the clicked signal with the QSignalMapper
171 connect(ui->quickConfigHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
172 connect(ui->quickPubIdHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
173 connect(ui->quickHotpLenHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
174 connect(ui->quickSecretKeyHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
175
176 connect(ui->advConfigHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
177 connect(ui->advParamGenSchemeHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
178 connect(ui->advPubIdHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
179 connect(ui->advHotpLenHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
180 connect(ui->advHotpParamsHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
181 connect(ui->advSecretKeyHelpBtn, SIGNAL(clicked()), mapper, SLOT(map()));
182
183 //Set a value for each button
184 mapper->setMapping(ui->quickConfigHelpBtn, HelpBox::Help_ConfigurationSlot);
185 mapper->setMapping(ui->quickPubIdHelpBtn, HelpBox::Help_OathPublicID);
186 mapper->setMapping(ui->quickHotpLenHelpBtn, HelpBox::Help_HotpLen);
187 mapper->setMapping(ui->quickSecretKeyHelpBtn, HelpBox::Help_SecretKey);
188
189 mapper->setMapping(ui->advConfigHelpBtn, HelpBox::Help_ConfigurationSlot);
190 mapper->setMapping(ui->advParamGenSchemeHelpBtn, HelpBox::Help_ParameterGeneration);
191 mapper->setMapping(ui->advPubIdHelpBtn, HelpBox::Help_OathPublicID);
192 mapper->setMapping(ui->advHotpLenHelpBtn, HelpBox::Help_HotpLen);
193 mapper->setMapping(ui->advHotpParamsHelpBtn, HelpBox::Help_HotpParam);
194 mapper->setMapping(ui->advSecretKeyHelpBtn, HelpBox::Help_SecretKey);
195
196 //Connect the mapper
197 connect(mapper, SIGNAL(mapped(int)), this, SIGNAL(showHelp(int)));
198 connect(ui->advConfigProtectionBox, SIGNAL(showHelp(int)), this, SIGNAL(showHelp(int)));
199 }
200
keyFound(bool found,bool * featuresMatrix)201 void OathPage::keyFound(bool found, bool* featuresMatrix) {
202 if(found) {
203 if(m_state == State_Initial) {
204 ui->quickWriteConfigBtn->setEnabled(true);
205 ui->advWriteConfigBtn->setEnabled(true);
206 ui->advExportConfigBtn->setEnabled(true);
207
208 if(!featuresMatrix[YubiKeyFinder::Feature_MultipleConfigurations]) {
209 ui->quickConfigSlot2Radio->setEnabled(false);
210 ui->advConfigSlot2Radio->setEnabled(false);
211 } else {
212 ui->quickConfigSlot2Radio->setEnabled(true);
213 ui->advConfigSlot2Radio->setEnabled(true);
214 }
215
216 if(!featuresMatrix[YubiKeyFinder::Feature_MovingFactor]) {
217 ui->advMovingFactorSeedCombo->setEnabled(false);
218 ui->advMovingFactorSeedTxt->setEnabled(false);
219 }
220
221 if(!featuresMatrix[YubiKeyFinder::Feature_OathHotp]) {
222 this->setEnabled(false);
223 }
224
225 if(this->currentIndex() == Page_Quick) {
226 resetQuickPrefix();
227 }
228 } else if(this->currentIndex() == Page_Advanced &&
229 m_state >= State_Programming_Multiple &&
230 m_keyPresent == false) {
231 if(m_state == State_Programming_Multiple) {
232 ui->advWriteConfigBtn->setEnabled(true);
233 ui->advExportConfigBtn->setEnabled(true);
234 } else {
235 writeAdvConfig(WRITE_CONFIG);
236 }
237 }
238 m_keyPresent = true;
239 } else {
240
241 ui->quickWriteConfigBtn->setEnabled(false);
242 ui->advWriteConfigBtn->setEnabled(false);
243 ui->advExportConfigBtn->setEnabled(false);
244
245 m_keyPresent = false;
246
247 if(m_state == State_Initial) {
248 ui->quickConfigSlot2Radio->setEnabled(true);
249 ui->advConfigSlot2Radio->setEnabled(true);
250
251 ui->advMovingFactorSeedCombo->setEnabled(true);
252 if(ui->advMovingFactorSeedCombo->currentIndex() == MOVING_FACTOR_ZERO) {
253 ui->advMovingFactorSeedTxt->setEnabled(false);
254 } else {
255 ui->advMovingFactorSeedTxt->setEnabled(true);
256 }
257
258 this->setEnabled(true);
259 } else if(this->currentIndex() == Page_Advanced &&
260 m_state >= State_Programming_Multiple) {
261 if(m_keysProgrammedCtr > 0 && !m_ready) {
262 changeAdvConfigParams();
263 }
264 }
265 }
266 }
267
clearState()268 void OathPage::clearState() {
269 m_state = State_Initial;
270 m_ready = true;
271
272 if(m_ykConfig != 0) {
273 delete m_ykConfig;
274 m_ykConfig = 0;
275 }
276 }
277
updatePrefix()278 void OathPage::updatePrefix() {
279 if(m_currentPage == Page_Quick || m_customerPrefix > 0) {
280 //OMP
281 m_pubId[0] = YUBICO_OMP_CODE;
282
283 //TT
284 m_pubId[1] = OATH_HOTP_CUSTOMER_PREFIX_START +
285 (unsigned char) (m_customerPrefix / 1000);
286
287 if(m_customerPrefix > 0) {
288 // make room for the prefix..
289 m_pubIdMUI %= 99999;
290 int mui_part = m_customerPrefix % 1000;
291 m_pubIdMUI += mui_part * 100000;
292 }
293 }
294
295 QString pubIdTxt;
296 QString muiTxt = QString::number(m_pubIdMUI).rightJustified(8, '0');
297 QString pubIdModhexTxt = YubiKeyUtil::qstrModhexEncode(
298 m_pubId, 2);
299
300 switch(m_currentPage) {
301 case Page_Quick:
302 ui->quickPrefixTxt->setText(pubIdModhexTxt.left(4));
303 ui->quickMUITxt->setText(muiTxt);
304 break;
305
306 case Page_Advanced:
307 switch(ui->advPubIdFormatCombo->currentIndex()){
308 case OATH_FIXED_NUMERIC:
309 fixBCD(m_pubId, 2);
310 pubIdTxt = YubiKeyUtil::qstrHexEncode(
311 m_pubId, 2);
312
313 ui->advOMPTxt->setText(pubIdTxt.left(2));
314 ui->advTTTxt->setText(pubIdTxt.mid(2, 2));
315 ui->advMUITxt->setText(muiTxt);
316 break;
317
318 case OATH_FIXED_MODHEX1:
319 fixBCD(m_pubId + 1, 1);
320 pubIdTxt = YubiKeyUtil::qstrHexEncode(
321 m_pubId, 2);
322
323 ui->advOMPTxt->setText(pubIdModhexTxt.left(2));
324 ui->advTTTxt->setText(pubIdTxt.mid(2, 2));
325 ui->advMUITxt->setText(muiTxt);
326 break;
327
328 case OATH_FIXED_MODHEX2:
329 ui->advOMPTxt->setText(pubIdModhexTxt.left(2));
330 ui->advTTTxt->setText(pubIdModhexTxt.mid(2, 2));
331 ui->advMUITxt->setText(muiTxt);
332 break;
333
334 case OATH_FIXED_MODHEX:
335 unsigned char tempMUI[4];
336 tempMUI[0] = (m_pubIdMUI >> 24) & 0xff;
337 tempMUI[1] = (m_pubIdMUI >> 16) & 0xff;
338 tempMUI[2] = (m_pubIdMUI >> 8) & 0xff;
339 tempMUI[3] = m_pubIdMUI & 0xff;
340 muiTxt = YubiKeyUtil::qstrModhexEncode(tempMUI, 4);
341 ui->advOMPTxt->setText(pubIdModhexTxt.left(2));
342 ui->advTTTxt->setText(pubIdModhexTxt.mid(2, 2));
343 ui->advMUITxt->setText(muiTxt);
344 break;
345 }
346
347 break;
348 }
349 }
350
fixBCD(unsigned char * bp,int bcnt)351 void OathPage::fixBCD(unsigned char *bp, int bcnt) {
352 while (bcnt--) {
353 if ((*bp & 0x0f) > 0x09) *bp -= 0x09;
354 if ((*bp & 0xf0) > 0x90) *bp -= 0x90;
355 bp++;
356 }
357 }
358
loadSettings()359 void OathPage::loadSettings() {
360 QSettings settings;
361 m_customerPrefix = settings.value(SG_CUSTOMER_PREFIX).toInt();
362
363 if(m_customerPrefix > 0) {
364 ui->advPubIdFormatCombo->setCurrentIndex(OATH_FIXED_MODHEX2);
365 }
366 bool customerPrefixFlag = !(m_customerPrefix > 0);
367
368 ui->advPubIdFormatCombo->setEnabled(customerPrefixFlag);
369 ui->advOMPTxt->setEnabled(customerPrefixFlag);
370 ui->advTTTxt->setEnabled(customerPrefixFlag);
371
372 ui->advExportConfigBtn->setVisible(settings.value(SG_EXPORT_PREFERENCE).toBool());
373
374 bool hotp8 = settings.value(SG_OATH_HOTP8).toBool();
375 ui->advHotpLen6Radio->setChecked(!hotp8);
376 ui->quickHotpLen6Radio->setChecked(!hotp8);
377 ui->advHotpLen8Radio->setChecked(hotp8);
378 ui->quickHotpLen8Radio->setChecked(hotp8);
379 }
380
381 /*
382 Quick Page handling
383 */
resetQuickPage()384 void OathPage::resetQuickPage() {
385 memset(&m_pubId, 0, sizeof(m_pubId));
386
387 if(ui->quickConfigSlot1Radio->isChecked()) {
388 ui->quickConfigSlot2Radio->setChecked(true);
389 }
390
391 ui->quickPubIdCheck->setChecked(true);
392
393 on_quickResetBtn_clicked();
394 }
395
on_quickResetBtn_clicked()396 void OathPage::on_quickResetBtn_clicked() {
397 resetQuickPrefix();
398
399 ui->quickSecretKeyTxt->setText(
400 YubiKeyUtil::generateRandomHex((size_t)KEY_SIZE_OATH * 2));
401 on_quickSecretKeyTxt_editingFinished();
402 }
403
on_quickHideParams_clicked(bool checked)404 void OathPage::on_quickHideParams_clicked(bool checked) {
405 if(checked) {
406 ui->quickSecretKeyTxt->setEchoMode(QLineEdit::Password);
407 } else {
408 ui->quickSecretKeyTxt->setEchoMode(QLineEdit::Normal);
409 }
410 }
411
on_quickPubIdCheck_stateChanged(int state)412 void OathPage::on_quickPubIdCheck_stateChanged(int state) {
413 bool disable = (state != 0);
414
415 ui->quickPrefixTxt->setEnabled(disable);
416 ui->quickMUITxt->setEnabled(disable);
417 ui->quickMUIGenerateBtn->setEnabled(disable);
418 }
419
resetQuickPrefix()420 void OathPage::resetQuickPrefix() {
421 ui->quickMUITxt->setText(
422 QString::number(YubiKeyFinder::getInstance()->serial()));
423
424 updateQuickMUI();
425 updatePrefix();
426 }
427
updateQuickMUI()428 void OathPage::updateQuickMUI() {
429 QString txt = ui->quickMUITxt->text();
430
431 unsigned char buf[MAX_SIZE];
432 memset(buf, 0, sizeof(buf));
433 size_t bufLen = 0;
434
435 YubiKeyUtil::qstrClean(&txt, OATH_HOTP_MUI_SIZE * 2, true);
436 YubiKeyUtil::qstrDecDecode(buf, &bufLen, txt);
437
438 ui->quickMUITxt->setText(txt);
439 memcpy(m_pubId + 2, buf, OATH_HOTP_MUI_SIZE);
440 }
441
on_quickMUITxt_editingFinished()442 void OathPage::on_quickMUITxt_editingFinished() {
443 updateQuickMUI();
444 updatePrefix();
445 }
446
on_quickMUIGenerateBtn_clicked()447 void OathPage::on_quickMUIGenerateBtn_clicked() {
448 YubiKeyUtil::generateRandom((unsigned char*)&m_pubIdMUI, sizeof(m_pubIdMUI));
449 m_pubIdMUI %= 99999999;
450 updatePrefix();
451 }
452
on_quickSecretKeyTxt_editingFinished()453 void OathPage::on_quickSecretKeyTxt_editingFinished() {
454 QString txt = ui->quickSecretKeyTxt->text();
455 YubiKeyUtil::qstrClean(&txt, (size_t)KEY_SIZE_OATH * 2);
456 ui->quickSecretKeyTxt->setText(txt);
457 }
458
validateQuickSettings()459 bool OathPage::validateQuickSettings() {
460 if(!(ui->quickConfigSlot1Radio->isChecked() ||
461 ui->quickConfigSlot2Radio->isChecked())) {
462 emit showStatusMessage(tr(ERR_CONF_SLOT_NOT_SELECTED), 1);
463 return false;
464 }
465
466 QSettings settings;
467
468 //Check if configuration slot 1 is being programmed
469 if (!settings.value(SG_OVERWRITE_CONF_SLOT1).toBool() &&
470 ui->quickConfigSlot1Radio->isChecked()) {
471 //Confirm from client
472 ConfirmBox confirm(this);
473 confirm.setConfirmIndex(ConfirmBox::Confirm_ConfigurationSlot);
474 int ret = confirm.exec();
475
476 switch (ret) {
477 case 1: //Yes
478 break;
479 default: //No
480 return false;
481 }
482 }
483 return true;
484 }
485
writeQuickConfig()486 void OathPage::writeQuickConfig() {
487 //Clear status
488 emit showStatusMessage(NULL, -1);
489
490 //Validate settings
491 if(!validateQuickSettings()) {
492 return;
493 }
494
495 //
496 m_state = State_Programming;
497
498 //Write configuration
499 ui->quickWriteConfigBtn->setEnabled(false);
500 ui->quickResetBtn->setEnabled(false);
501 ui->quickBackBtn->setEnabled(false);
502
503 if(m_ykConfig != 0) {
504 delete m_ykConfig;
505 m_ykConfig = 0;
506 }
507 m_ykConfig = new YubiKeyConfig();
508
509 //Programming mode...
510 m_ykConfig->setProgrammingMode(YubiKeyConfig::Mode_OathHotp);
511
512 // set serial
513 m_ykConfig->setSerial(QString::number(YubiKeyFinder::getInstance()->serial()));
514
515 //Configuration slot...
516 int configSlot = 1;
517 if(ui->quickConfigSlot2Radio->isChecked()) {
518 configSlot = 2;
519 }
520 m_ykConfig->setConfigSlot(configSlot);
521
522 //Public ID...
523 if(ui->quickPubIdCheck->isChecked()) {
524 m_ykConfig->setPubIdTxt(getPublicId(true));
525
526 //OATH Public ID Type...
527 m_ykConfig->setOathFixedModhex2(true);
528 }
529
530 //HOTP Len...
531 m_ykConfig->setOathHotp8(ui->quickHotpLen8Radio->isChecked());
532
533 //HOTP Moving Factor Seed...
534 m_ykConfig->setOathMovingFactorSeed(0);
535
536 //Secret Key...
537 m_ykConfig->setSecretKeyTxt(ui->quickSecretKeyTxt->text());
538
539 //Write
540 connect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
541 this, SLOT(quickConfigWritten(bool, const QString &)));
542
543 YubiKeyWriter::getInstance()->writeConfig(m_ykConfig);
544 }
545
quickConfigWritten(bool written,const QString & msg)546 void OathPage::quickConfigWritten(bool written, __attribute__((unused)) const QString &msg) {
547
548 disconnect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
549 this, SLOT(quickConfigWritten(bool, const QString &)));
550
551 ui->quickWriteConfigBtn->setEnabled(true);
552 ui->quickResetBtn->setEnabled(true);
553 ui->quickBackBtn->setEnabled(true);
554
555 if(written && m_ykConfig != 0) {
556 QString keyDetail("");
557 if(ui->quickPubIdCheck->isChecked()) {
558 QString pubIdTxt = ui->quickPrefixTxt->text() +
559 ui->quickMUITxt->text().replace(QRegExp("\\s"), QString(""));
560
561 keyDetail = tr(" (OATH ID: %1)").arg(pubIdTxt);
562 }
563
564 showStatusMessage(tr(KEY_CONFIGURED).arg(keyDetail), 0);
565 }
566
567 clearState();
568 }
569
570 /*
571 Advanced Page handling
572 */
resetAdvPage()573 void OathPage::resetAdvPage() {
574 memset(&m_pubId, 0, sizeof(m_pubId));
575 m_pubIdMUI = 0;
576
577 bool customerPrefixFlag = !(m_customerPrefix > 0);
578
579 if(ui->advConfigSlot1Radio->isChecked()) {
580 ui->advConfigSlot2Radio->setChecked(true);
581 }
582
583 ui->advConfigParamsCombo->setCurrentIndex(0);
584 ui->advAutoProgramKeysCheck->setChecked(false);
585 ui->advProgramMulKeysBox->setChecked(false);
586
587 ui->advConfigProtectionBox->reset();
588
589 ui->advPubIdCheck->setChecked(true);
590 if(customerPrefixFlag) {
591 ui->advPubIdFormatCombo->setCurrentIndex(OATH_FIXED_NUMERIC);
592 } else {
593 ui->advPubIdFormatCombo->setCurrentIndex(OATH_FIXED_MODHEX2);
594 }
595 ui->advPubIdFormatCombo->setEnabled(customerPrefixFlag);
596 on_advOMPTxt_editingFinished();
597 ui->advOMPTxt->setEnabled(customerPrefixFlag);
598 on_advTTTxt_editingFinished();
599 ui->advTTTxt->setEnabled(customerPrefixFlag);
600 on_advMUITxt_editingFinished();
601
602 ui->advMovingFactorSeedCombo->setCurrentIndex(0);
603 ui->advMovingFactorSeedTxt->setText(tr("0"));
604 ui->advMovingFactorSeedTxt->setEnabled(false);
605
606 ui->advSecretKeyTxt->clear();
607 on_advSecretKeyTxt_editingFinished();
608
609 ui->advStopBtn->setEnabled(false);
610 }
611
freezeAdvPage(bool freeze)612 void OathPage::freezeAdvPage(bool freeze) {
613 bool disable = !freeze;
614 ui->advConfigBox->setEnabled(disable);
615 ui->advProgramMulKeysBox->setEnabled(disable);
616 ui->advConfigProtectionBox->setEnabled(disable);
617 ui->advKeyParamsBox->setEnabled(disable);
618
619 ui->advWriteConfigBtn->setEnabled(disable);
620 ui->advExportConfigBtn->setEnabled(disable);
621 ui->advStopBtn->setEnabled(!disable);
622 ui->advResetBtn->setEnabled(disable);
623 ui->advBackBtn->setEnabled(disable);
624 }
625
on_advProgramMulKeysBox_clicked(bool checked)626 void OathPage::on_advProgramMulKeysBox_clicked(bool checked) {
627 if(checked) {
628 changeAdvConfigParams();
629 }
630 }
631
on_advConfigParamsCombo_currentIndexChanged(int index)632 void OathPage::on_advConfigParamsCombo_currentIndexChanged(__attribute__((unused)) int index) {
633 changeAdvConfigParams();
634 }
635
on_advPubIdCheck_stateChanged(int state)636 void OathPage::on_advPubIdCheck_stateChanged(int state) {
637 bool disable = (state != 0);
638
639 if(m_customerPrefix <= 0) {
640 ui->advPubIdFormatCombo->setEnabled(disable);
641 ui->advOMPTxt->setEnabled(disable);
642 ui->advTTTxt->setEnabled(disable);
643 }
644
645 ui->advMUITxt->setEnabled(disable);
646 ui->advMUIGenerateBtn->setEnabled(disable);
647 }
648
on_advPubIdFormatCombo_currentIndexChanged(int index)649 void OathPage::on_advPubIdFormatCombo_currentIndexChanged(__attribute__((unused)) int index) {
650 updatePrefix();
651 }
652
updateAdvOMP(int index)653 void OathPage::updateAdvOMP(int index) {
654 QString txt = ui->advOMPTxt->text();
655
656 unsigned char buf[MAX_SIZE];
657 memset(buf, 0, sizeof(buf));
658 size_t bufLen = 0;
659
660 if (index == OATH_FIXED_NUMERIC) {
661 YubiKeyUtil::qstrClean(&txt, OATH_HOTP_OMP_SIZE * 2, true);
662 YubiKeyUtil::qstrDecDecode(buf, &bufLen, txt);
663 } else {
664 YubiKeyUtil::qstrModhexClean(&txt, OATH_HOTP_OMP_SIZE * 2);
665 YubiKeyUtil::qstrModhexDecode(buf, &bufLen, txt);
666 }
667 ui->advOMPTxt->setText(txt);
668 memcpy(m_pubId + 0, buf, OATH_HOTP_OMP_SIZE);
669 }
670
on_advOMPTxt_editingFinished()671 void OathPage::on_advOMPTxt_editingFinished() {
672 updateAdvOMP(ui->advPubIdFormatCombo->currentIndex());
673 updatePrefix();
674 }
675
updateAdvTT(int index)676 void OathPage::updateAdvTT(int index) {
677 QString txt = ui->advTTTxt->text();
678
679 unsigned char buf[MAX_SIZE];
680 memset(buf, 0, sizeof(buf));
681 size_t bufLen = 0;
682
683 if (index == OATH_FIXED_NUMERIC ||
684 index == OATH_FIXED_MODHEX1) {
685 YubiKeyUtil::qstrClean(&txt, OATH_HOTP_TT_SIZE * 2, true);
686 YubiKeyUtil::qstrDecDecode(buf, &bufLen, txt);
687 } else {
688 YubiKeyUtil::qstrModhexClean(&txt, OATH_HOTP_TT_SIZE * 2);
689 YubiKeyUtil::qstrModhexDecode(buf, &bufLen, txt);
690 }
691 ui->advTTTxt->setText(txt);
692 memcpy(m_pubId + 1, buf, OATH_HOTP_TT_SIZE);
693 }
694
on_advTTTxt_editingFinished()695 void OathPage::on_advTTTxt_editingFinished() {
696 updateAdvTT(ui->advPubIdFormatCombo->currentIndex());
697 updatePrefix();
698 }
699
updateAdvMUI(int index)700 void OathPage::updateAdvMUI(int index) {
701 QString txt = ui->advMUITxt->text();
702
703 if (index != OATH_FIXED_MODHEX) {
704 YubiKeyUtil::qstrClean(&txt, OATH_HOTP_MUI_SIZE * 2, true);
705 m_pubIdMUI = txt.toInt();
706 } else {
707 unsigned char buf[MAX_SIZE];
708 memset(buf, 0, sizeof(buf));
709 size_t bufLen = 0;
710
711 YubiKeyUtil::qstrModhexClean(&txt, OATH_HOTP_MUI_SIZE * 2);
712 YubiKeyUtil::qstrModhexDecode(buf, &bufLen, txt);
713 m_pubIdMUI = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3]);
714 }
715 }
716
on_advMUITxt_editingFinished()717 void OathPage::on_advMUITxt_editingFinished() {
718 updateAdvMUI(ui->advPubIdFormatCombo->currentIndex());
719 updatePrefix();
720 }
721
on_advMUIGenerateBtn_clicked()722 void OathPage::on_advMUIGenerateBtn_clicked() {
723 YubiKeyUtil::generateRandom((unsigned char*)&m_pubIdMUI, sizeof(m_pubIdMUI));
724 m_pubIdMUI %= 99999999;
725 updatePrefix();
726 }
727
on_advMovingFactorSeedCombo_currentIndexChanged(int index)728 void OathPage::on_advMovingFactorSeedCombo_currentIndexChanged(int index) {
729 switch(index) {
730 case MOVING_FACTOR_ZERO:
731 ui->advMovingFactorSeedTxt->setText("0");
732 ui->advMovingFactorSeedTxt->setEnabled(false);
733 break;
734 case MOVING_FACTOR_FIXED:
735 ui->advMovingFactorSeedTxt->setEnabled(true);
736 break;
737 case MOVING_FACTOR_RAND:
738 unsigned int tmp;
739 YubiKeyUtil::generateRandom((unsigned char *) &tmp, sizeof(tmp));
740 ui->advMovingFactorSeedTxt->setText(QString::number(tmp));
741 on_advMovingFactorSeedTxt_editingFinished();
742 ui->advMovingFactorSeedTxt->setEnabled(true);
743 break;
744 }
745 }
746
on_advMovingFactorSeedTxt_editingFinished()747 void OathPage::on_advMovingFactorSeedTxt_editingFinished() {
748 unsigned int val = ui->advMovingFactorSeedTxt->text().toUInt();
749 val = (((val + 8) >> 4UL) & 0xffff) << 4UL;
750 ui->advMovingFactorSeedTxt->setText(QString::number(val));
751 }
752
on_advSecretKeyTxt_editingFinished()753 void OathPage::on_advSecretKeyTxt_editingFinished() {
754 QString txt = ui->advSecretKeyTxt->text();
755 YubiKeyUtil::qstrClean(&txt, (size_t)KEY_SIZE_OATH * 2);
756 ui->advSecretKeyTxt->setText(txt);
757 }
758
on_advSecretKeyGenerateBtn_clicked()759 void OathPage::on_advSecretKeyGenerateBtn_clicked() {
760 ui->advSecretKeyTxt->setText(
761 YubiKeyUtil::generateRandomHex((size_t)KEY_SIZE_OATH * 2));
762 ui->advSecretKeyTxt->setCursorPosition(0);
763 }
764
on_advWriteConfigBtn_clicked()765 void OathPage::on_advWriteConfigBtn_clicked() {
766 emit showStatusMessage(NULL, -1);
767
768 if(!ui->advProgramMulKeysBox->isChecked()) {
769 m_keysProgrammedCtr = 0;
770 }
771
772 //Validate settings
773 if(!validateAdvSettings()) {
774 return;
775 }
776
777 clearState();
778
779 freezeAdvPage(true);
780
781 // Change state
782 if(ui->advProgramMulKeysBox->isChecked()) {
783 if(ui->advAutoProgramKeysCheck->isChecked()) {
784 m_keysProgrammedCtr = 0;
785 m_state = State_Programming_Multiple_Auto;
786 } else {
787 m_state = State_Programming_Multiple;
788 }
789 } else {
790 m_keysProgrammedCtr = 0;
791 m_state = State_Programming;
792 }
793
794 writeAdvConfig(WRITE_CONFIG);
795 }
796
on_advExportConfigBtn_clicked()797 void OathPage::on_advExportConfigBtn_clicked() {
798 emit showStatusMessage(NULL, -1);
799
800 //Validate settings
801 if(!validateAdvSettings()) {
802 return;
803 }
804
805 clearState();
806
807 freezeAdvPage(true);
808
809 writeAdvConfig(EXPORT_CONFIG);
810 }
811
on_advStopBtn_clicked()812 void OathPage::on_advStopBtn_clicked() {
813 ui->advStopBtn->setEnabled(false);
814 m_state = State_Initial;
815 stopAdvConfigWritting();
816 }
817
stopAdvConfigWritting()818 void OathPage::stopAdvConfigWritting() {
819 qDebug() << "Stopping adv configuration writing...";
820
821 if(m_state >= State_Programming_Multiple) {
822 ui->advStopBtn->setEnabled(true);
823 return;
824 }
825
826 m_keysProgrammedCtr = 0;
827 clearState();
828
829 freezeAdvPage(false);
830 ui->advResetBtn->setEnabled(true);
831 }
832
changeAdvConfigParams()833 void OathPage::changeAdvConfigParams() {
834 int index = ui->advConfigParamsCombo->currentIndex();
835 int idScheme = GEN_SCHEME_FIXED;
836 int secretScheme = GEN_SCHEME_FIXED;
837
838 switch(index) {
839 case SCHEME_INCR_ID_RAND_SECRET:
840 //Increment IDs only if in programming mode
841 if(m_state != State_Initial) {
842 idScheme = GEN_SCHEME_INCR;
843 }
844 secretScheme = GEN_SCHEME_RAND;
845 break;
846
847 case SCHEME_RAND_ALL:
848 idScheme = GEN_SCHEME_RAND;
849 secretScheme = GEN_SCHEME_RAND;
850 break;
851 }
852
853 //Public ID...
854 if(ui->advPubIdCheck->isChecked()) {
855 switch(idScheme) {
856 case GEN_SCHEME_INCR:
857 {
858 m_pubIdMUI++;
859 updatePrefix();
860 }
861 break;
862
863 case GEN_SCHEME_RAND:
864 YubiKeyUtil::generateRandom((unsigned char*)&m_pubIdMUI, sizeof(m_pubIdMUI));
865 m_pubIdMUI %= 99999999;
866
867 updatePrefix();
868 break;
869 }
870 }
871
872 //HOTP Moving Factor Seed...
873 if(ui->advMovingFactorSeedCombo->currentIndex() == MOVING_FACTOR_RAND) {
874 unsigned int tmp;
875 YubiKeyUtil::generateRandom((unsigned char *) &tmp, sizeof(tmp));
876 ui->advMovingFactorSeedTxt->setText(QString::number(tmp));
877 on_advMovingFactorSeedTxt_editingFinished();
878 }
879
880 //Secret Key...
881 QString secretKeyTxt = YubiKeyUtil::getNextHex(
882 KEY_SIZE_OATH * 2,
883 ui->advSecretKeyTxt->text(), secretScheme);
884 ui->advSecretKeyTxt->setText(secretKeyTxt);
885 on_advSecretKeyTxt_editingFinished();
886 m_ready = true;
887 }
888
validateAdvSettings()889 bool OathPage::validateAdvSettings() {
890 if(!(ui->advConfigSlot1Radio->isChecked() ||
891 ui->advConfigSlot2Radio->isChecked())) {
892 emit showStatusMessage(tr(ERR_CONF_SLOT_NOT_SELECTED), 1);
893 return false;
894 }
895
896 QSettings settings;
897
898 //Check if configuration slot 1 is being programmed
899 if (!settings.value(SG_OVERWRITE_CONF_SLOT1).toBool() &&
900 ui->advConfigSlot1Radio->isChecked() &&
901 m_keysProgrammedCtr == 0) {
902 //Confirm from client
903 ConfirmBox confirm(this);
904 confirm.setConfirmIndex(ConfirmBox::Confirm_ConfigurationSlot);
905 int ret = confirm.exec();
906
907 switch (ret) {
908 case 1: //Yes
909 break;
910 default: //No
911 return false;
912 }
913 }
914
915 if(!ui->advConfigProtectionBox->checkConfirm()) {
916 return false;
917 }
918
919 return true;
920 }
921
getPublicId(bool bcd)922 QString OathPage::getPublicId(bool bcd) {
923 unsigned char pubId[6];
924 memcpy(pubId, m_pubId, 2);
925
926 if(bcd) {
927 int part = m_pubIdMUI / 1000000;
928 pubId[2] = ((part / 10) << 4) + part % 10;
929 part = m_pubIdMUI / 10000 % 100;
930 pubId[3] = ((part / 10) << 4) + part % 10;
931 part = m_pubIdMUI / 100 % 100;
932 pubId[4] = ((part / 10) << 4) + part % 10;
933 part = m_pubIdMUI % 100;
934 pubId[5] = ((part / 10) << 4) + part % 10;
935 } else {
936 pubId[2] = (m_pubIdMUI >> 24) & 0xff;
937 pubId[3] = (m_pubIdMUI >> 16) & 0xff;
938 pubId[4] = (m_pubIdMUI >> 8) & 0xff;
939 pubId[5] = m_pubIdMUI & 0xff;
940 }
941 QString pubIdTxt = YubiKeyUtil::qstrModhexEncode(pubId, 6);
942 return pubIdTxt;
943 }
944
writeAdvConfig(int mode)945 void OathPage::writeAdvConfig(int mode) {
946 qDebug() << "Writing configuration...";
947
948 //Disable stop button while configuration is being written
949 ui->advStopBtn->setEnabled(false);
950
951
952 //Write configuration
953 if(m_ykConfig != 0) {
954 qDebug() << "ykConfig destroyed";
955 delete m_ykConfig;
956 m_ykConfig = 0;
957 }
958 m_ykConfig = new YubiKeyConfig();
959
960 //Programming mode...
961 m_ykConfig->setProgrammingMode(YubiKeyConfig::Mode_OathHotp);
962
963 // set serial
964 m_ykConfig->setSerial(QString::number(YubiKeyFinder::getInstance()->serial()));
965
966 //Configuration slot...
967 int configSlot = 1;
968 if(ui->advConfigSlot2Radio->isChecked()) {
969 configSlot = 2;
970 }
971 m_ykConfig->setConfigSlot(configSlot);
972
973 //Public ID...
974 if(ui->advPubIdCheck->isChecked()) {
975 bool bcd = ui->advPubIdFormatCombo->currentIndex() < 3 ? true : false;
976 m_ykConfig->setPubIdTxt(getPublicId(bcd));
977
978 //OATH Public ID Type...
979 switch(ui->advPubIdFormatCombo->currentIndex()) {
980 case 1:
981 m_ykConfig->setOathFixedModhex1(true);
982 break;
983 case 2:
984 m_ykConfig->setOathFixedModhex2(true);
985 break;
986 case 3:
987 m_ykConfig->setOathFixedModhex(true);
988 break;
989 }
990 }
991
992 //HOTP Len...
993 m_ykConfig->setOathHotp8(ui->advHotpLen8Radio->isChecked());
994
995 //HOTP Moving Factor Seed...
996 if(YubiKeyFinder::getInstance()->checkFeatureSupport(
997 YubiKeyFinder::Feature_MovingFactor)) {
998
999 m_ykConfig->setOathMovingFactorSeed(
1000 ui->advMovingFactorSeedTxt->text().toUInt());
1001 }
1002
1003 //Secret Key...
1004 m_ykConfig->setSecretKeyTxt(ui->advSecretKeyTxt->text());
1005
1006 //Configuration protection...
1007 m_ykConfig->setCurrentAccessCodeTxt(
1008 ui->advConfigProtectionBox->currentAccessCode());
1009 m_ykConfig->setNewAccessCodeTxt(
1010 ui->advConfigProtectionBox->newAccessCode(),
1011 ui->advConfigProtectionBox->newAccMode());
1012
1013 if(mode == WRITE_CONFIG) {
1014 //Write
1015 connect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
1016 this, SLOT(advConfigWritten(bool, const QString &)));
1017
1018 YubiKeyWriter::getInstance()->writeConfig(m_ykConfig);
1019 } else if(mode == EXPORT_CONFIG) {
1020 connect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
1021 this, SLOT(advConfigExported(bool, const QString &)));
1022
1023 YubiKeyWriter::getInstance()->exportConfig(m_ykConfig);
1024 }
1025 }
1026
advConfigWritten(bool written,const QString & msg)1027 void OathPage::advConfigWritten(bool written, const QString &msg) {
1028 disconnect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
1029 this, SLOT(advConfigWritten(bool, const QString &)));
1030
1031 QString message;
1032
1033 if(written && m_ykConfig != 0) {
1034 qDebug() << "Configuration written....";
1035
1036 m_keysProgrammedCtr++;
1037
1038 QString keyDetail("");
1039 if(ui->advPubIdCheck->isChecked()) {
1040
1041 QString pubIdTxt = ui->advOMPTxt->text() +
1042 ui->advTTTxt->text() +
1043 ui->advMUITxt->text().replace(QRegExp("\\s"), QString(""));
1044
1045 keyDetail = tr(" (OATH ID: %1)").arg(pubIdTxt);
1046 }
1047
1048 if(m_state == State_Programming){
1049 message = tr(KEY_CONFIGURED).arg(keyDetail);
1050 } else {
1051 message = tr("%1. %2").arg(tr(KEY_CONFIGURED).arg(keyDetail)).arg(tr(REMOVE_KEY));
1052 }
1053
1054 showStatusMessage(message, 0);
1055
1056 message = tr(KEY_CONFIGURED).arg("");
1057 } else {
1058 qDebug() << "Configuration could not be written....";
1059
1060 message = msg;
1061 }
1062
1063 advUpdateResults(written, message);
1064
1065 m_ready = false;
1066 stopAdvConfigWritting();
1067 }
1068
advConfigExported(bool written,const QString & msg)1069 void OathPage::advConfigExported(bool written, const QString &msg) {
1070 disconnect(YubiKeyWriter::getInstance(), SIGNAL(configWritten(bool, const QString &)),
1071 this, SLOT(advConfigExported(bool, const QString &)));
1072
1073 QString message;
1074
1075 if(written && m_ykConfig != 0) {
1076 qDebug() << "Configuration exported....";
1077
1078 message = tr(KEY_EXPORTED);
1079
1080 showStatusMessage(message, 0);
1081 } else {
1082 qDebug() << "Configuration could not be exported....";
1083
1084 message = msg;
1085 }
1086
1087 m_ready = false;
1088 stopAdvConfigWritting();
1089 }
1090
advUpdateResults(bool written,const QString & msg)1091 void OathPage::advUpdateResults(bool written, const QString &msg) {
1092 int row = 0;
1093
1094 ui->advResultsWidget->insertRow(row);
1095
1096 //Sr. No....
1097 QTableWidgetItem *srnoItem = new QTableWidgetItem(
1098 tr("%1").arg(ui->advResultsWidget->rowCount()));
1099 if(written) {
1100 srnoItem->setIcon(QIcon(QPixmap(tr(":/res/images/tick.png"))));
1101 } else {
1102 srnoItem->setIcon(QIcon(QPixmap(tr(":/res/images/cross.png"))));
1103 }
1104 srnoItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
1105 ui->advResultsWidget->setItem(row, 0, srnoItem);
1106
1107
1108 //Public ID...
1109 QString pubIdTxt;
1110 if(ui->advPubIdCheck->isChecked() && m_ykConfig != 0) {
1111 pubIdTxt = ui->advOMPTxt->text() +
1112 ui->advTTTxt->text() +
1113 ui->advMUITxt->text().replace(QRegExp("\\s"), QString(""));
1114 } else {
1115 pubIdTxt = NA;
1116 }
1117 QTableWidgetItem *idItem = new QTableWidgetItem(
1118 tr("%1").arg(pubIdTxt));
1119 idItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
1120 ui->advResultsWidget->setItem(row, 1, idItem);
1121
1122
1123 //Status...
1124 QTableWidgetItem *statusItem = new QTableWidgetItem(
1125 tr("%1").arg(msg));
1126 statusItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
1127 ui->advResultsWidget->setItem(row, 2, statusItem);
1128
1129
1130 //Timestamp...
1131 QDateTime timstamp = QDateTime::currentDateTime();
1132 QTableWidgetItem *timeItem = new QTableWidgetItem(
1133 tr("%1").arg(timstamp.toString(Qt::SystemLocaleShortDate)));
1134 timeItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
1135 ui->advResultsWidget->setItem(row, 3, timeItem);
1136
1137
1138 ui->advResultsWidget->resizeColumnsToContents();
1139 ui->advResultsWidget->resizeRowsToContents();
1140 }
1141
hotpLen_clicked()1142 void OathPage::hotpLen_clicked() {
1143 QSettings settings;
1144 QRadioButton *button = ui->advHotpLen8Radio;
1145 QRadioButton *button2 = ui->quickHotpLen8Radio;
1146 if(m_currentPage == Page_Quick) {
1147 button = ui->quickHotpLen8Radio;
1148 button2 = ui->advHotpLen8Radio;
1149 }
1150 if(button->isChecked()) {
1151 settings.setValue(SG_OATH_HOTP8, true);
1152 } else {
1153 settings.setValue(SG_OATH_HOTP8, false);
1154 }
1155 button2->toggle();
1156 }
1157
setCurrentSlot(int slot)1158 void OathPage::setCurrentSlot(int slot) {
1159 if(m_currentPage == Page_Advanced) {
1160 ui->advConfigSlot1Radio->setChecked(slot == 1);
1161 ui->advConfigSlot2Radio->setChecked(slot == 2);
1162 } else if(m_currentPage == Page_Quick) {
1163 ui->quickConfigSlot1Radio->setChecked(slot == 1);
1164 ui->quickConfigSlot2Radio->setChecked(slot == 2);
1165 }
1166 }
1167