-int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
- long *len)
- {
- EVP_ENCODE_CTX ctx;
- int end=0,i,k,bl=0,hl=0,nohead=0;
- char buf[256];
- BUF_MEM *nameB;
- BUF_MEM *headerB;
- BUF_MEM *dataB,*tmpB;
-
- nameB=BUF_MEM_new();
- headerB=BUF_MEM_new();
- dataB=BUF_MEM_new();
- if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL))
- {
- PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
- return(0);
- }
-
- buf[254]='\0';
- for (;;)
- {
- i=BIO_gets(bp,buf,254);
-
- if (i <= 0)
- {
- PEMerr(PEM_F_PEM_READ_BIO,PEM_R_NO_START_LINE);
- goto err;
- }
-
- while ((i >= 0) && (buf[i] <= ' ')) i--;
- buf[++i]='\n'; buf[++i]='\0';
-
- if (strncmp(buf,"-----BEGIN ",11) == 0)
- {
- i=strlen(&(buf[11]));
-
- if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0)
- continue;
- if (!BUF_MEM_grow(nameB,i+9))
- {
- PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memcpy(nameB->data,&(buf[11]),i-6);
- nameB->data[i-6]='\0';
- break;
- }
- }
- hl=0;
- if (!BUF_MEM_grow(headerB,256))
- { PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
- headerB->data[0]='\0';
- for (;;)
- {
- i=BIO_gets(bp,buf,254);
- if (i <= 0) break;
-
- while ((i >= 0) && (buf[i] <= ' ')) i--;
- buf[++i]='\n'; buf[++i]='\0';
-
- if (buf[0] == '\n') break;
- if (!BUF_MEM_grow(headerB,hl+i+9))
- { PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
- if (strncmp(buf,"-----END ",9) == 0)
- {
- nohead=1;
- break;
- }
- memcpy(&(headerB->data[hl]),buf,i);
- headerB->data[hl+i]='\0';
- hl+=i;
- }
-
- bl=0;
- if (!BUF_MEM_grow(dataB,1024))
- { PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
- dataB->data[0]='\0';
- if (!nohead)
- {
- for (;;)
- {
- i=BIO_gets(bp,buf,254);
- if (i <= 0) break;
-
- while ((i >= 0) && (buf[i] <= ' ')) i--;
- buf[++i]='\n'; buf[++i]='\0';
-
- if (i != 65) end=1;
- if (strncmp(buf,"-----END ",9) == 0)
- break;
- if (i > 65) break;
- if (!BUF_MEM_grow_clean(dataB,i+bl+9))
- {
- PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memcpy(&(dataB->data[bl]),buf,i);
- dataB->data[bl+i]='\0';
- bl+=i;
- if (end)
- {
- buf[0]='\0';
- i=BIO_gets(bp,buf,254);
- if (i <= 0) break;
-
- while ((i >= 0) && (buf[i] <= ' ')) i--;
- buf[++i]='\n'; buf[++i]='\0';
-
- break;
- }
- }
- }
- else
- {
- tmpB=headerB;
- headerB=dataB;
- dataB=tmpB;
- bl=hl;
- }
- i=strlen(nameB->data);
- if ( (strncmp(buf,"-----END ",9) != 0) ||
- (strncmp(nameB->data,&(buf[9]),i) != 0) ||
- (strncmp(&(buf[9+i]),"-----\n",6) != 0))
- {
- PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_END_LINE);
- goto err;
- }
-
- EVP_DecodeInit(&ctx);
- i=EVP_DecodeUpdate(&ctx,
- (unsigned char *)dataB->data,&bl,
- (unsigned char *)dataB->data,bl);
- if (i < 0)
- {
- PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
- goto err;
- }
- i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k);
- if (i < 0)
- {
- PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
- goto err;
- }
- bl+=k;
-
- if (bl == 0) goto err;
- *name=nameB->data;
- *header=headerB->data;
- *data=(unsigned char *)dataB->data;
- *len=bl;
- OPENSSL_free(nameB);
- OPENSSL_free(headerB);
- OPENSSL_free(dataB);
- return(1);
+ if (got_header == MAYBE_HEADER) {
+ if (memchr(linebuf, ':', len) != NULL)
+ got_header = IN_HEADER;
+ }
+ if (!strncmp(linebuf, endstr, ENDLEN) || got_header == IN_HEADER)
+ flags_mask &= ~PEM_FLAG_ONLY_B64;
+ len = sanitize_line(linebuf, len, flags & flags_mask);
+
+ /* Check for end of header. */
+ if (linebuf[0] == '\n') {
+ if (got_header == POST_HEADER) {
+ /* Another blank line is an error. */
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
+ goto err;
+ }
+ got_header = POST_HEADER;
+ tmp = *data;
+ continue;
+ }
+
+ /* Check for end of stream (which means there is no header). */
+ if (strncmp(linebuf, endstr, ENDLEN) == 0) {
+ p = linebuf + ENDLEN;
+ namelen = strlen(name);
+ if (strncmp(p, name, namelen) != 0 ||
+ strncmp(p + namelen, tailstr, TAILLEN) != 0) {
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
+ goto err;
+ }
+ if (got_header == MAYBE_HEADER) {
+ *header = *data;
+ *data = tmp;
+ }
+ break;
+ } else if (end) {
+ /* Malformed input; short line not at end of data. */
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
+ goto err;
+ }
+ /*
+ * Else, a line of text -- could be header or data; we don't
+ * know yet. Just pass it through.
+ */
+ BIO_puts(tmp, linebuf);
+ /*
+ * Only encrypted files need the line length check applied.
+ */
+ if (got_header == POST_HEADER) {
+ /* 65 includes the trailing newline */
+ if (len > 65)
+ goto err;
+ if (len < 65)
+ end = 1;
+ }
+ }
+
+ ret = 1;