コード例 #1
0
ファイル: rfc822.c プロジェクト: chr15m/ccan
struct bytestring rfc822_header_unfolded_value(struct rfc822_msg *msg,
					       struct rfc822_header *hdr)
{
	struct bytestring raw = rfc822_header_raw_value(msg, hdr);
	struct bytestring next, rest;
	int lines = 0;
	size_t len = 0;

	if (!hdr->unfolded.ptr) {
		rest = raw;
		while (rest.ptr) {
			get_line(rest, &next, &rest);
			lines++;
			len += next.len;
		}

		if (lines <= 1) {
			hdr->unfolded = bytestring(raw.ptr, len);
		} else {
			char *unfold = tal_arr(msg, char, len);
			char *p = unfold;

			ALLOC_CHECK(unfold, bytestring_NULL);

			rest = raw;
			while (rest.ptr) {
				get_line(rest, &next, &rest);
				memcpy(p, next.ptr, next.len);
				p += next.len;
			}

			assert(p == (unfold + len));
			hdr->unfolded = bytestring(unfold, len);
		}
	}
コード例 #2
0
ファイル: rfc822.c プロジェクト: chr15m/ccan
static void get_line(struct bytestring in, struct bytestring *first,
		     struct bytestring *rest)
{
	size_t rawlen, trimlen;
	const char *inp = in.ptr;
	const char *nl;

	nl = memchr(inp, '\n', in.len);
	if (!nl)
		rawlen = in.len;
	else
		rawlen = nl - inp + 1;

	trimlen = rawlen;
	if ((trimlen > 0) && (inp[trimlen-1] == '\n')) {
		trimlen--;
		if ((trimlen > 0) && (inp[trimlen-1] == '\r'))
			trimlen--;
	}

	*first = bytestring(in.ptr, trimlen);

	if (rawlen < in.len)
		*rest = bytestring(in.ptr + rawlen, in.len - rawlen);
	else
		*rest = bytestring_NULL;
}
コード例 #3
0
ファイル: rfc822.c プロジェクト: chr15m/ccan
static struct rfc822_header *next_header_parse(struct rfc822_msg *msg)
{
	const char *h, *eh, *ev, *colon;
	struct rfc822_header *hi;

	CHECK(msg, ">next_header_parse");

	if (!msg->remainder)
		return NULL;

	if (msg->body && (msg->remainder >= msg->body))
		return NULL;

	h = msg->remainder;
	eh = next_line(h, msg->end);

	ev = eh;
	if ((ev > h) && (ev[-1] == '\n'))
		ev--;
	if ((ev > h) && (ev[-1] == '\r'))
		ev--;
	if (ev == h) {
		/* Found the end of the headers */

		assert(!msg->body || (msg->body == eh));

		if (eh < msg->end)
			msg->body = eh;
		return NULL;
	}

	while ((eh < msg->end) && rfc822_iswsp(*eh))
		eh = next_line(eh, msg->end);

	if (eh >= msg->end)
		msg->remainder = NULL;
	else
		msg->remainder = eh;


	hi = talz(msg, struct rfc822_header);
	ALLOC_CHECK(hi, NULL);

	hi->all = bytestring(h, eh - h);
	list_add_tail(&msg->headers, &hi->list);

	colon = memchr(h, ':', hi->all.len);
	if (colon) {
		hi->rawname = bytestring(h, colon - h);
		hi->rawvalue = bytestring(colon + 1, eh - colon - 1);
	} else {
		hi->rawname = bytestring_NULL;
		hi->rawvalue = bytestring_NULL;
	}

	CHECK(msg, "<next_header_parse");

	return index_header(msg, hi);
}
コード例 #4
0
ファイル: rfc822.c プロジェクト: chr15m/ccan
struct bytestring rfc822_body(struct rfc822_msg *msg)
{
	CHECK(msg, ">rfc822_body");

	if (!msg->body && msg->remainder) {
		const char *p, *q;

		p = memmem(msg->remainder, msg->end - msg->remainder,
			   "\n\r\n", 3);
		q = memmem(msg->remainder, msg->end - msg->remainder,
			   "\n\n", 2);

		if (p && (!q || (p < q)))
			msg->body = p + 3;
		else if (q && (!p || (q < p)))
			msg->body = q + 2;

		if (msg->body >= msg->end) {
			assert(msg->body == msg->end);
			msg->body = NULL;
		}
	}

	CHECK(msg, "<rfc822_body");

	if (msg->body)
		return bytestring(msg->body, msg->end - msg->body);
	else
		return bytestring_NULL;
}
コード例 #5
0
ファイル: bytestring.c プロジェクト: HSchroeder/ccan
static struct bytestring _splitchr(struct bytestring whole, char delim,
				   size_t start)
{
	const char *p;

	assert(start <= whole.len);

	/* Check this first, in case memchr() is not safe with zero length */
	if (start == whole.len)
		return bytestring(whole.ptr + start, 0);

	p = memchr(whole.ptr + start, delim, whole.len - start);
	if (p)
		return bytestring_slice(whole, start, p - whole.ptr);
	else
		return bytestring_slice(whole, start, whole.len);
}
コード例 #6
0
ファイル: fancy.cpp プロジェクト: GnunuX/e2guardian
// download body for this request
int fancydm::in(DataBuffer * d, Socket * sock, Socket * peersock, class HTTPHeader * requestheader, class HTTPHeader * docheader, bool wantall, int *headersent, bool * toobig)
{

	//DataBuffer *d = where to stick the data back into
	//Socket *sock = where to read from
	//Socket *peersock = browser to send stuff to for keeping it alive
	//HTTPHeader *docheader = header used for sending first line of reply
	//HTTPHeader *requestheader = header client used to request
	//bool wantall = to determine if just content filter or a full scan
	//int *headersent = to use to send the first line of header if needed
	//                  or to mark the header has already been sent
	//bool *toobig = flag to modify to say if it could not all be downloaded

#ifdef DGDEBUG
	std::cout << "Inside fancy download manager plugin" << std::endl;
#endif

	int rc;

	off_t newsize;
	off_t expectedsize = docheader->contentLength();
	off_t bytessec = 0;
	off_t bytesgot = 0;
	int percentcomplete = 0;
	unsigned int eta = 0;
	int timeelapsed = 0;

	// if using non-persistent connections, some servers will not report
	// a content-length. in these situations, just download everything.
	bool geteverything = false;
	if ((expectedsize < 0) && !(docheader->isPersistent()))
		geteverything = true;
	if (expectedsize < 0)
		expectedsize = 0;

	bool initialsent = false;

	String message, jsmessage;

	char *block = NULL;  // buffer for storing a grabbed block from the input stream
	char *temp = NULL;

	bool swappedtodisk = false;

	struct timeval starttime;
	struct timeval themdays;
	struct timeval nowadays;
	gettimeofday(&themdays, NULL);
	gettimeofday(&starttime, NULL);
	
	toobig_unscanned = false;
	toobig_notdownloaded = false;
	bool secondstage = false;
	
	// buffer size for streaming downloads
	off_t blocksize = 32768;
	// set to a sensible minimum
	if (!wantall && (blocksize > o.max_content_filter_size))
		blocksize = o.max_content_filter_size;
	else if (wantall && (blocksize > o.max_content_ramcache_scan_size))
		blocksize = o.max_content_ramcache_scan_size;
#ifdef DGDEBUG
	std::cout << "blocksize: " << blocksize << std::endl;
#endif

	// determine downloaded filename
	String filename(requestheader->disposition());
	if (filename.length() == 0) {
		filename = requestheader->getUrl();
		filename = requestheader->decode(filename);
		if (filename.contains("?"))
			filename = filename.before("?");
		while (filename.contains("/"))
			filename = filename.after("/");
	}

	while ((bytesgot < expectedsize) || geteverything) {
		// send text header to show status
		if (o.trickle_delay > 0) {
			gettimeofday(&nowadays, NULL);
			timeelapsed = nowadays.tv_sec - starttime.tv_sec;
			if ((!initialsent && timeelapsed > o.initial_trickle_delay) || (initialsent && nowadays.tv_sec - themdays.tv_sec > o.trickle_delay)) {
				initialsent = true;
				bytessec = bytesgot / timeelapsed;
				themdays.tv_sec = nowadays.tv_sec;
				if ((*headersent) < 1) {
#ifdef DGDEBUG
					std::cout << "sending header for text status" << std::endl;
#endif
					message = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n";
					// Output initial template
					std::deque<String>::iterator i = progresspage.html.begin();
					std::deque<String>::iterator penultimate = progresspage.html.end()-1;
					bool newline;
					while (i != progresspage.html.end()) {
						newline = false;
						message = *i;
						if (message == "-FILENAME-") {
							message = filename;
						}
						else if (message == "-FILESIZE-") {
							message = String(expectedsize);
						}
						else if (message == "-SERVERIP-") {
							message = peersock->getLocalIP();
						}
						else if ((i == penultimate) || ((*(i+1))[0] != '-')) {
							newline = true;
						}
						peersock->writeString(message.toCharArray());
						// preserve line breaks from the original template file
						if (newline)
							peersock->writeString("\n");
						i++;
					}
					// send please wait message for non-JS-enabled browsers
					// 1200 "Please wait - downloading to be scanned..."
					message = "<noscript><p>";
					message += o.language_list.getTranslation(1200);
					message += "</p></noscript>\n";
					peersock->writeString(message.toCharArray());
					(*headersent) = 2;
				}
#ifdef DGDEBUG
				std::cout << "trickle delay - sending progress..." << std::endl;
#endif
				message = "Downloading status: ";
				// Output a call to template's JavaScript progressupdate function
				jsmessage = "<script language='javascript'>\n<!--\nprogressupdate(" + String(bytesgot) + "," + String(bytessec) + ");\n//-->\n</script>";
				peersock->writeString(jsmessage.toCharArray());
				// send text only version for non-JS-enabled browsers.
				// checkme: translation?
				if (geteverything) {
					message = "<noscript><p>Time remaining: unknown; "
						+ bytestring(bytessec) + "/s; total downloaded: " + bytestring(bytesgot) + "</p></noscript>\n";
				} else {
					percentcomplete = bytesgot/(expectedsize/100);
					eta = (expectedsize-bytesgot)/bytessec;
					message = "<noscript><p>" + String(percentcomplete) + "%, time remaining: " + timestring(eta) + "; "
						+ bytestring(bytessec) + "/s; total downloaded: " + bytestring(bytesgot) + "</p></noscript>\n";
				}
				peersock->writeString(message.toCharArray());
				peersock->writeString("<!-- force flush -->\r\n");
			}
		}

		if (wantall) {
			if (!swappedtodisk) {
				// if not swapped to disk and file is too large for RAM, then swap to disk
				if (bytesgot > o.max_content_ramcache_scan_size) {
#ifdef DGDEBUG
					std::cout << "swapping to disk" << std::endl;
#endif
					d->tempfilefd = d->getTempFileFD();
					if (d->tempfilefd < 0) {
#ifdef DGDEBUG
						std::cerr << "error buffering to disk so skipping disk buffering" << std::endl;
#endif
						syslog(LOG_ERR, "%s", "error buffering to disk so skipping disk buffering");
						(*toobig) = true;
						break;
					}
					writeEINTR(d->tempfilefd, d->data, d->buffer_length);
					swappedtodisk = true;
					d->tempfilesize = d->buffer_length;
				}
			} else if (bytesgot > o.max_content_filecache_scan_size) {
				(*toobig) = true;
				toobig_unscanned = true;
				if (geteverything && (upperlimit > 0)) {
					// multi-stage download enabled, and we don't know content length
					if ((!secondstage) && initialsent) {
						secondstage = true;
						// send download size warning message
						jsmessage = "<script language='javascript'>\n<!--\ndownloadwarning(" + String(upperlimit) + ");\n//-->\n</script>";
						peersock->writeString(jsmessage.toCharArray());
						// text-only version
						message = "<noscript><p>";
						// 1201 Warning: file too large to scan. If you suspect that this file is larger than
						// 1202 , then refresh to download directly.
						message += o.language_list.getTranslation(1201);
						message += bytestring(upperlimit);
						message += o.language_list.getTranslation(1202);
						message += "</p></noscript>\n";
						peersock->writeString(message.toCharArray());
						peersock->writeString("<!-- force flush -->\r\n");
						// add URL to clean cache (for all groups)
						String url(requestheader->getUrl());
						addToClean(url, o.filter_groups + 1);
#ifdef DGDEBUG
						std::cout << "fancydm: file too big to be scanned, entering second stage of download" << std::endl;
#endif
					}

					// too large to even download, let alone scan
					if (bytesgot > upperlimit) {
#ifdef DGDEBUG
						std::cout << "fancydm: file too big to be downloaded, halting second stage of download" << std::endl;
#endif
						toobig_unscanned = false;
						toobig_notdownloaded = true;
						break;
					}
				} else {
					// multi-stage download disabled, or we know content length
					// if swapped to disk and file too large for that too, then give up
#ifdef DGDEBUG
					std::cout << "fancydm: file too big to be scanned, halting download" << std::endl;
#endif
					toobig_unscanned = false;
					toobig_notdownloaded = true;
					break;
				}
			}
		} else {
			if (bytesgot > o.max_content_filter_size) {
				// if we aren't downloading for virus scanning, and file too large for filtering, give up
#ifdef DGDEBUG
				std::cout << "fancydm: file too big to be filtered, halting download" << std::endl;
#endif
				(*toobig) = true;
				break;
			}
		}

		if (!swappedtodisk) {
			if (d->buffer_length >= blocksize) {
				newsize = d->buffer_length;
			} else {
				newsize = blocksize;
			}
#ifdef DGDEBUG
			std::cout << "newsize: " << newsize << std::endl;
#endif
			// if not getting everything until connection close, grab only what is left
			if (!geteverything && (newsize > (expectedsize - bytesgot)))
				newsize = expectedsize - bytesgot;
			delete[] block;
			block = new char[newsize];
			try {
				sock->checkForInput(d->timeout);
			} catch(std::exception & e) {
				break;
			}
			// improved more efficient socket read which uses the buffer better
			rc = d->bufferReadFromSocket(sock, block, newsize, d->timeout, o.trickle_delay);
			// grab a block of input, doubled each time

			if (rc <= 0) {
				break;  // an error occured so end the while()
				// or none received so pipe is closed
			}
			else {
				/*if (d->data != temp)
					delete[] temp;*/
				temp = new char[d->buffer_length + rc + 1];  // replacement store
				temp[d->buffer_length + rc] = '\0';
				memcpy(temp, d->data, d->buffer_length);  // copy the current data
				memcpy(temp + d->buffer_length, block, rc);  // copy the new data
				delete[]d->data;  // delete the current data block
				d->data = temp;
				temp = NULL;
				d->buffer_length += rc;  // update data size counter
			}
		} else {
			try {
				sock->checkForInput(d->timeout);
			}
			catch(std::exception & e) {
				break;
			}
			rc = d->bufferReadFromSocket(sock, d->data,
				// if not getting everything until connection close, grab only what is left
				(!geteverything && ((expectedsize - bytesgot) < d->buffer_length) ? (expectedsize - bytesgot) : d->buffer_length), d->timeout);
			if (rc <= 0) {
				break;
			}
			else {
				lseek(d->tempfilefd, 0, SEEK_END);  // not really needed
				writeEINTR(d->tempfilefd, d->data, rc);
				d->tempfilesize += rc;
#ifdef DGDEBUG
				std::cout << "written to disk: " << rc << " total: " << d->tempfilesize << std::endl;
#endif
			}
		}
		if (d->tempfilesize > 0) {
			bytesgot = d->tempfilesize;
		} else {
			bytesgot = d->buffer_length;
		}
	}

	if (initialsent) {

		if (!swappedtodisk) {	// if we sent textual content then we can't
			// stream the file to the user so we must save to disk for them
			// to download by clicking on the magic link
			// You can get to this point by having a large ram cache, or
			// slow internet connection with small initial trickle delay.
			// This should be rare.
#ifdef DGDEBUG
			std::cout << "swapping to disk" << std::endl;
#endif
			d->tempfilefd = d->getTempFileFD();
			if (d->tempfilefd < 0) {
#ifdef DGDEBUG
				std::cerr << "error buffering complete to disk so skipping disk buffering" << std::endl;
#endif
				syslog(LOG_ERR, "error buffering complete to disk so skipping disk buffering");
			} else {
				writeEINTR(d->tempfilefd, d->data, d->buffer_length);
				swappedtodisk = true;
				d->tempfilesize = d->buffer_length;
			}
		}

		// Output a call to template's JavaScript nowscanning function
		peersock->writeString("<script language='javascript'>\n<!--\nnowscanning();\n//-->\n</script>\n");
		// send text-only version
		// 1210 "Download Complete. Starting scan..."
		if (!(toobig_unscanned || toobig_notdownloaded)) {
			message = "<noscript><p>";
			message += o.language_list.getTranslation(1210);
			message += "</p></noscript>\n";
			peersock->writeString(message.toCharArray());
		}
		// only keep full downloads
		if (!toobig_notdownloaded)
			(*d).preservetemp = true;
		(*d).dontsendbody = true;
	}

	if (!(*toobig) && !swappedtodisk) {	// won't deflate stuff swapped to disk
		if (d->decompress.contains("deflate")) {
#ifdef DGDEBUG
			std::cout << "zlib format" << std::endl;
#endif
			d->zlibinflate(false);  // incoming stream was zlib compressed
		}
		else if (d->decompress.contains("gzip")) {
#ifdef DGDEBUG
			std::cout << "gzip format" << std::endl;
#endif
			d->zlibinflate(true);  // incoming stream was gzip compressed
		}
	}
	d->bytesalreadysent = 0;
	/*if (d->data != temp)
		delete[] temp;*/
	delete[] block;
	return 0;
}
コード例 #7
0
void pivacy_cardemu_emulator::process_prove_commitment(bytestring& c_apdu, bytestring& r_apdu)
{
	if (!proof_started || !proof_have_context_and_D || (selected_credential == NULL))
	{
		r_apdu = SW_WRONG_STATE;
		reset_proof();
	}
	else if ((c_apdu.size() < 5) || (c_apdu[OFS_LC] != (SYSPAR(l_statzk) / 8)))
	{
		r_apdu = SW_LENGTH_ERROR;
		reset_proof();
	}
	else if ((c_apdu[OFS_P1] != 0x00) || (c_apdu[OFS_P2] != 0x00))
	{
		r_apdu = SW_DATA_UNKNOWN;
		reset_proof();
	}
	else
	{
		// Retrieve the nonce
		bytestring nonce = c_apdu.substr(OFS_CDATA, c_apdu[OFS_LC]);
		
		// Generate the proof
		silvia_prover prover(selected_credential->get_issuer_public_key(), selected_credential->get_silvia_credential());
		
		mpz_class c;
		mpz_class A_prime;
		mpz_class e_hat;
		mpz_class v_prime_hat;
		std::vector<mpz_class> a_i_hat;
		std::vector<silvia_attribute*> a_i;
		
		prover.prove(curproof_D, nonce.mpz_val(), curproof_context.mpz_val(), c, A_prime, e_hat, v_prime_hat, a_i_hat, a_i);
		
		// Save proof output
		std::vector<mpz_class>::iterator a_i_hat_it = a_i_hat.begin();
		std::vector<silvia_attribute*>::iterator a_i_it = a_i.begin();
		
		curproof_A_prime = bytestring(A_prime);
		curproof_e_hat = bytestring(e_hat);
		curproof_v_prime_hat = bytestring(v_prime_hat);
		
		/* Add hidden master secret */
		curproof_attributes.push_back(bytestring(*a_i_hat_it));
		a_i_hat_it++;
		
		for (std::vector<bool>::iterator i = curproof_D.begin(); i != curproof_D.end(); i++)
		{
			if ((*i) == true)
			{
				curproof_attributes.push_back(bytestring((*a_i_it)->rep()));
				a_i_it++;
			}
			else
			{
				curproof_attributes.push_back(bytestring(*a_i_hat_it));
				a_i_hat_it++;
			}
		}
		
		// Return c
		r_apdu = bytestring(c);
		r_apdu += SW_OK;
		
		proof_proved = true;
	}
}
コード例 #8
0
std::vector<bytestring> silvia_irma_issuer::get_issue_commands_round_1()
{
	assert(irma_issuer_state == IRMA_ISSUER_SELECTED);
	
	std::vector<bytestring> commands;
	
	////////////////////////////////////////////////////////////////////
	// Step 3: start issuance
	////////////////////////////////////////////////////////////////////
	
	// FIXME: context is randomly generated and kept as state!
	mpz_class context_mpz = silvia_rng::i()->get_random(SYSPAR(l_H));
	context = bytestring(context_mpz);
	bytestring id;
	id += (unsigned char) ((ispec->get_credential_id() & 0xff00) >> 8);
	id += (unsigned char) (ispec->get_credential_id() & 0x00ff);
	
	bytestring attr_count;
	attr_count += (unsigned char) ((ispec->get_attributes().size() + 1) & 0xff00) >> 8; // +1 for expires
	attr_count += (unsigned char) ((ispec->get_attributes().size() + 1) & 0x00ff); 		// +1 for expires
	
	// FIXME: actually do something with these flags!
	bytestring attr_flags = "000000";
	
	bytestring timestamp = (unsigned long) time(NULL);
	timestamp = timestamp.substr(timestamp.size() - 4);
	
	PAD_TO_SYSPAR(context, l_H);
	
	silvia_apdu issue_start(0x80, 0x10, 0x00, 0x00);
	
	issue_start.append_data(id);
	issue_start.append_data(attr_count);
	issue_start.append_data(attr_flags);
	issue_start.append_data(context);
	issue_start.append_data(timestamp);
	
	commands.push_back(issue_start.get_apdu());
	
	////////////////////////////////////////////////////////////////////
	// Step 4: write the public key to the card
	////////////////////////////////////////////////////////////////////
	
	// n
	silvia_apdu issue_set_n(0x80, 0x11, 0x00, 0x00);
	bytestring n(pubkey->get_n());
	
	// Pad if necessary
	PAD_TO_SYSPAR(n, l_n);
	
	issue_set_n.append_data(n);
	
	commands.push_back(issue_set_n.get_apdu());
	
	// S
	silvia_apdu issue_set_S(0x80, 0x11, 0x01, 0x00);
	bytestring S(pubkey->get_S());
	
	// Pad if necessary
	PAD_TO_SYSPAR(S, l_n);
	
	issue_set_S.append_data(S);
	
	commands.push_back(issue_set_S.get_apdu());
	
	// Z
	silvia_apdu issue_set_Z(0x80, 0x11, 0x02, 0x00);
	bytestring Z(pubkey->get_Z());
	
	// Pad if necessary
	PAD_TO_SYSPAR(Z, l_n);
	
	issue_set_Z.append_data(Z);
	
	commands.push_back(issue_set_Z.get_apdu());
	
	for (int i = 0; i < (ispec->get_attributes().size() + 2); i++)
	{
		silvia_apdu issue_set_R(0x80, 0x11, 0x03, (unsigned char) (0x00 + i));
		
		bytestring R(pubkey->get_R()[i]);
		
		// Pad if necessary
		PAD_TO_SYSPAR(R, l_n);
		
		issue_set_R.append_data(R);
		
		commands.push_back(issue_set_R.get_apdu());
	}
	
	////////////////////////////////////////////////////////////////////
	// Step 5: write the attributes to the card
	////////////////////////////////////////////////////////////////////
	
	issue_attributes.clear();
	
	// Create the "expires+metadata" attribute
	bytestring expires_and_metadata;
	
	// Add metadata version number
	expires_and_metadata += IRMA_CREDENTIAL_METADATA_VERSION;
	
	// Add expiration date
	int expires = ispec->get_expires();
	
	expires_and_metadata += (unsigned char) ((expires & 0x00ff0000) >> 16);
	expires_and_metadata += (unsigned char) ((expires & 0x0000ff00) >> 8);
	expires_and_metadata += (unsigned char)  (expires & 0x000000ff);
	
	// Add credential ID
	expires_and_metadata += (unsigned char) ((ispec->get_credential_id() & 0xff00) >> 8);
	expires_and_metadata += (unsigned char) (ispec->get_credential_id() & 0x00ff);
	
	metadata_attribute = new silvia_integer_attribute(expires_and_metadata.mpz_val());
	
	silvia_apdu write_expires_attr(0x80, 0x12, 0x01, 0x00);
	
	write_expires_attr.append_data(metadata_attribute->bs_rep());
	
	commands.push_back(write_expires_attr.get_apdu());
	
	issue_attributes.push_back(metadata_attribute);
	
	// Create all other attributes
	unsigned char ctr = 0x02;
	
	for (std::vector<silvia_attribute*>::iterator i = ispec->get_attributes().begin(); i != ispec->get_attributes().end(); i++, ctr++)
	{
		silvia_apdu write_attr(0x80, 0x12, ctr, 0x00);
		write_attr.append_data((*i)->bs_rep());
		
		commands.push_back(write_attr.get_apdu());
		
		issue_attributes.push_back(*i);
	}
	
	issuer->set_attributes(issue_attributes);
	
	////////////////////////////////////////////////////////////////////
	// Step 6: get issue commitment from card
	////////////////////////////////////////////////////////////////////
	
	silvia_apdu issue_commitment_nonce(0x80, 0x1a, 0x00, 0x00);
	
	bytestring n1(issuer->get_issuer_nonce());
	
	// pad if necessary
	PAD_TO_SYSPAR(n1, l_statzk);
	
	silvia_apdu issue_commitment(0x80, 0x1a, 0x00, 0x00);
	issue_commitment.append_data(n1);
	
	commands.push_back(issue_commitment.get_apdu());
	
	////////////////////////////////////////////////////////////////////
	// Step 7: get proof values c, v'^, s^
	////////////////////////////////////////////////////////////////////
	
	silvia_apdu get_proof_c(0x80, 0x1b, 0x01, 0x00);
	silvia_apdu get_proof_v_prime_hat(0x80, 0x1b, 0x02, 0x00);
	silvia_apdu get_proof_s_hat(0x80, 0x1b, 0x03, 0x00);
	
	commands.push_back(get_proof_c.get_apdu());
	commands.push_back(get_proof_v_prime_hat.get_apdu());
	commands.push_back(get_proof_s_hat.get_apdu());
	
	////////////////////////////////////////////////////////////////////
	// Step 8: get card nonce n2
	////////////////////////////////////////////////////////////////////
	
	silvia_apdu get_card_nonce_n2(0x80, 0x1c, 0x00, 0x00);
	
	commands.push_back(get_card_nonce_n2.get_apdu());
	
	irma_issuer_state = IRMA_ISSUER_WAIT_COMMITMENT;
	
	return commands;
}